/* Memobox — visual language from the Claude Design project (Memobox.html):
   warm linen paper, terracotta accents, Lora serif headings, Caveat
   handwriting for captions, sepia photo tones. The memories overview is
   the cork pinboard ("Fotowand") from that design.

   Structure contract (ids/screens) unchanged — see index.html header. */

/* --- self-hosted fonts (local-only: no Google requests at runtime) --- */

@font-face { font-family: "Lora"; font-style: normal; font-weight: 500;
  src: url("/static/fonts/lora-500.woff2") format("woff2"); font-display: swap; }
@font-face { font-family: "Lora"; font-style: normal; font-weight: 600;
  src: url("/static/fonts/lora-600.woff2") format("woff2"); font-display: swap; }
@font-face { font-family: "Lora"; font-style: italic; font-weight: 400;
  src: url("/static/fonts/lora-400-italic.woff2") format("woff2"); font-display: swap; }
@font-face { font-family: "Nunito"; font-style: normal; font-weight: 400;
  src: url("/static/fonts/nunito-400.woff2") format("woff2"); font-display: swap; }
@font-face { font-family: "Nunito"; font-style: normal; font-weight: 600;
  src: url("/static/fonts/nunito-600.woff2") format("woff2"); font-display: swap; }
@font-face { font-family: "Nunito"; font-style: normal; font-weight: 700;
  src: url("/static/fonts/nunito-700.woff2") format("woff2"); font-display: swap; }
@font-face { font-family: "Caveat"; font-style: normal; font-weight: 500;
  src: url("/static/fonts/caveat-500.woff2") format("woff2"); font-display: swap; }
@font-face { font-family: "Caveat"; font-style: normal; font-weight: 600;
  src: url("/static/fonts/caveat-600.woff2") format("woff2"); font-display: swap; }

:root {
  /* paper / linen (design tokens.css) */
  --paper-0: #f6efd9;
  --paper-1: #f1e8d2;
  --paper-2: #ebdfbf;
  --paper-3: #ddcfa9;
  --paper-4: #c9b985;
  /* ink */
  --ink-0: #2a1f12;
  --ink-1: #4a3a22;
  --ink-2: #6a583a;
  --ink-3: #9a8866;
  /* accents */
  --terracotta: #b56a3b;
  --terracotta-deep: #8a4a25;
  --moss: #6a7a3a;
  --cream: #fcf3df;
  /* sepia photo tones */
  --sepia-1: #c9a877;
  --sepia-2: #a88450;
  /* night (device off) */
  --night-0: #1a1208;
  --night-1: #2a1f12;
  --night-2: #4a3a26;

  --focus: 0 0 0 4px var(--paper-1), 0 0 0 7px var(--terracotta);
  --ease-soft: cubic-bezier(0.45, 0.05, 0.2, 1);

  /* the room (desktop scenery — design system --room-*) */
  --room-wall: #e8dcbd;
  --room-floor: #caa46f;
  --room-rug: #b5764a;
  --room-sofa: #77874a;
  --room-sofa-2: #5d6b39;
  --room-wood: #8a6a3e;
  --room-cork: #c1935a;
  --room-glow: rgba(242, 217, 160, 0.55);
  --room-ceiling: #f3ecd6;
  --room-wall-side: #e0d2b0;
  --room-wall-lit: #f0e5c6;
  --room-day: rgba(255, 244, 214, 0.55);
  --shadow-card: 0 1px 2px rgba(60, 40, 20, 0.08), 0 4px 18px rgba(60, 40, 20, 0.10);
  --shadow-lift: 0 6px 16px rgba(60, 40, 20, 0.14), 0 24px 60px rgba(60, 40, 20, 0.14);

  --font-serif: "Lora", Georgia, serif;
  --font-sans: "Nunito", system-ui, sans-serif;
  --font-hand: "Caveat", "Bradley Hand", cursive;
  --font-mono: ui-monospace, "SF Mono", Menlo, monospace;

  --fs-base: 1.35rem;
  --fs-big: 1.8rem;
  --fs-display: 2.5rem;
  --radius: 18px;
  --ring-size: min(46vw, 240px);
  /* voice controls: one source of truth for the record button size and the
     footer ("dock") height, so every screen reserves the exact same space
     and text can never scroll under the button (see .controls / .transcript) */
  --ptt-size: min(38vw, 168px);
  --dock-h: calc(var(--ptt-size) + 3.6rem);
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body { height: 100%; }

body {
  font-family: var(--font-sans);
  color: var(--ink-0);
  font-size: var(--fs-base);
  line-height: 1.45;
  letter-spacing: 0.005em;
  transition: background 1.2s ease;
  overflow: hidden;
  background: var(--night-1);
  /* mobile app feel: no tap-flash, no rubber-band overscroll, no text select */
  -webkit-tap-highlight-color: transparent;
  overscroll-behavior: none;
  -webkit-user-select: none;
  user-select: none;
}

/* linen paper for the "on" screens */
body[data-screen="booting"],
body[data-screen="main_menu"],
body[data-screen="dialog"] {
  background:
    radial-gradient(ellipse at 20% 10%, rgba(255, 255, 255, 0.6), transparent 60%),
    radial-gradient(ellipse at 80% 90%, rgba(180, 150, 90, 0.10), transparent 60%),
    repeating-linear-gradient(0deg, rgba(120, 90, 40, 0.025) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(90deg, rgba(120, 90, 40, 0.025) 0 1px, transparent 1px 3px),
    var(--paper-1);
}
/* warm dark ambience when the device sleeps */
body[data-screen="off"], body[data-screen="login"], body[data-screen="person"] {
  background: radial-gradient(ellipse at 50% 60%, var(--night-2) 0%, var(--night-1) 70%, var(--night-0) 100%);
}
/* cork board behind the memories and the people wall */
body[data-screen="memories"], body[data-screen="people"] {
  background:
    radial-gradient(ellipse at 30% 20%, rgba(255, 230, 180, 0.25), transparent 60%),
    radial-gradient(ellipse at 80% 80%, rgba(80, 40, 10, 0.3), transparent 60%),
    repeating-radial-gradient(circle at 20% 30%, rgba(80, 40, 10, 0.12) 0 2px, transparent 2px 7px),
    repeating-radial-gradient(circle at 70% 60%, rgba(180, 120, 60, 0.1) 0 2px, transparent 2px 9px),
    repeating-radial-gradient(circle at 45% 80%, rgba(40, 20, 5, 0.08) 0 1px, transparent 1px 5px),
    linear-gradient(135deg, #c69a5a 0%, #a07640 100%);
}

.screen {
  display: none;
  position: fixed;
  inset: 0;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.4rem;
  padding: 1.5rem;
  max-width: 640px;
  margin: 0 auto;
}
body[data-screen="off"]        section[data-screen="off"],
body[data-screen="login"]      section[data-screen="login"],
body[data-screen="person"]     section[data-screen="person"],
body[data-screen="booting"]    section[data-screen="booting"],
body[data-screen="main_menu"]  section[data-screen="main_menu"],
body[data-screen="memories"]   section[data-screen="memories"],
body[data-screen="people"]     section[data-screen="people"],
body[data-screen="graph"]      section[data-screen="graph"],
body[data-screen="dialog"]     section[data-screen="dialog"] { display: flex; }
/* Gunter 2D screens (client-local, reachable only from the 2d hub) */
body[data-screen="choose_old"] section[data-screen="choose_old"],
body[data-screen="choose_new"] section[data-screen="choose_new"],
body[data-screen="quiz"]       section[data-screen="quiz"] { display: flex; }

body[data-screen="main_menu"] .screen,
body[data-screen="dialog"] .screen {
  /* reserve exactly the voice dock + home-indicator so content never
     scrolls under the record button */
  padding-bottom: calc(var(--dock-h) + env(safe-area-inset-bottom) + 1rem);
}

.screen-scroll {
  justify-content: flex-start;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding-top: calc(2.2rem + env(safe-area-inset-top));
  padding-bottom: calc(2rem + env(safe-area-inset-bottom));
}

/* --- type roles from the design --- */

.greeting {
  font-family: var(--font-serif);
  font-weight: 600;
  font-size: var(--fs-display);
  line-height: 1.12;
  letter-spacing: -0.01em;
  text-align: center;
  color: var(--ink-0);
}
.greeting-sub {
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 400;
  color: var(--ink-1);
  text-align: center;
  text-wrap: pretty;
}
.state-text {
  font-family: var(--font-serif);
  font-style: italic;
  color: var(--ink-2);
  font-size: 1.3rem;
  min-height: 1.5em;
  text-align: center;
}

/* --- login --- */

.login-card {
  background:
    radial-gradient(ellipse at 25% 15%, rgba(255, 255, 255, 0.55), transparent 60%),
    var(--paper-0);
  border: 1px solid rgba(60, 40, 20, 0.2);
  border-radius: var(--radius);
  padding: 2.2rem;
  width: min(90vw, 420px);
  display: flex;
  flex-direction: column;
  gap: 1rem;
  box-shadow: var(--shadow-lift);
}
/* Gate 2 (who is at the box): one card, four views — pick a person, type a
   password, register, or the admin door. Portraits come from the people
   wall, so a person recognises themselves rather than reading a list. */
.person-lead {
  font-family: var(--font-serif);
  font-size: var(--fs-lead, 1.25rem);
  color: var(--ink-0);
  margin: 0;
}
.person-view { display: flex; flex-direction: column; gap: 1rem; }
.person-hint {
  margin: -0.4rem 0 0;
  font-size: 0.85em;
  color: var(--ink-1);
  opacity: 0.75;
}
/* the live picture while the box looks: round, small, unmistakably ON */
.face-preview {
  width: min(52vw, 220px);
  aspect-ratio: 1;
  align-self: center;
  border-radius: 50%;
  overflow: hidden;
  background: rgba(60, 40, 20, 0.15);
  box-shadow: var(--shadow-lift);
}
.face-preview video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scaleX(-1);          /* mirror: a natural self-view */
}
/* pick view: the portraits keep their row; the actions below are a quiet
   centered column — "Neu hier" first, the camera retry beneath it */
.person-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.7rem;
}
#person-retry-face {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.9em;
}
#person-retry-face[hidden] { display: none; }
/* the Verwaltung door: present, findable, never competing with the people.
   Fixed to the viewport — the section only wraps the card, and "corner of
   the screen" means the screen. */
.admin-corner {
  position: fixed;
  bottom: 1rem;
  right: 1rem;
  z-index: 5;
  font-size: 0.8rem;
  padding: 0.4rem 0.8rem;
  opacity: 0.75;
}
.admin-corner[hidden] { display: none; }

/* Who is logged in — above the scenery, out of the way, always answerable. */
#account-chip {
  position: fixed;
  top: calc(0.7rem + env(safe-area-inset-top));
  right: calc(0.9rem + 52px + 0.8rem);   /* left of the view gear */
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.35rem 0.6rem 0.35rem 0.4rem;
  border-radius: 999px;
  background: var(--paper-0);
  border: 1px solid rgba(60, 40, 20, 0.2);
  box-shadow: var(--shadow-lift);
  font-size: 0.9rem;
}
#account-chip[hidden] { display: none; }
#account-chip img {
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  object-fit: cover;
  background: rgba(60, 40, 20, 0.12);
}
#account-chip img:not([src]) { visibility: hidden; }
#account-chip .btn { padding: 0.3rem 0.7rem; font-size: 0.85em; }
@media (max-width: 640px) {
  #account-chip {
    top: calc(0.7rem + env(safe-area-inset-top));
    right: calc(0.9rem + 52px + 0.6rem);
    font-size: 0.8rem;
  }
}
.person-view[hidden] { display: none; }
.person-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.8rem;
}
.person-list .btn {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  text-align: left;
}
.person-portrait {
  width: 2.6rem;
  height: 2.6rem;
  border-radius: 50%;
  object-fit: cover;
  background: rgba(60, 40, 20, 0.12);
  flex: none;
}
.person-role {
  display: block;
  font-size: 0.8em;
  opacity: 0.7;
}
.wordmark {
  font-family: var(--font-serif);
  font-size: var(--fs-display);
  font-weight: 600;
  color: var(--ink-0);
  display: flex;
  align-items: center;
  gap: 0.7rem;
}
.wordmark::before {
  content: "M";
  width: 2.4rem;
  height: 2.4rem;
  border-radius: 8px;
  background: var(--terracotta);
  color: var(--cream);
  font-size: 1.5rem;
  display: grid;
  place-items: center;
}
#login-form { display: flex; flex-direction: column; gap: 0.8rem; }
#login-form label {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-2);
}
#login-form input, .login-card .person-view input {
  font: inherit;
  font-size: var(--fs-base);
  padding: 0.7rem 0.9rem;
  border: 1.5px solid var(--paper-4);
  border-bottom-width: 3px;
  border-radius: 10px;
  background: #fffdf5;
  color: var(--ink-0);
}
#login-form input:focus-visible, .login-card .person-view input:focus-visible {
  outline: none;
  box-shadow: var(--focus);
}

/* --- buttons --- */

.btn {
  font: inherit;
  font-size: var(--fs-base);
  font-weight: 600;
  color: var(--ink-1);
  background: var(--paper-0);
  border: 1.5px solid var(--paper-4);
  border-bottom-width: 3px;
  border-radius: 14px;
  padding: 0.9rem 1.4rem;
  cursor: pointer;
  touch-action: manipulation;
}
.btn:focus-visible, .ptt:focus-visible, #power-button:focus-visible,
.polaroid:focus-visible {
  outline: none;
  box-shadow: var(--focus);
}
.btn-primary {
  background: var(--terracotta);
  border-color: var(--terracotta-deep);
  color: var(--cream);
}
.btn-big {
  width: 100%;
  font-family: var(--font-serif);
  font-weight: 500;
  font-size: var(--fs-big);
  padding: 1.4rem 1.6rem;
  display: flex;
  align-items: center;
  gap: 1rem;
  text-align: left;
  box-shadow: var(--shadow-card);
}
.btn-big:active { transform: translateY(2px); box-shadow: none; }
.btn-icon { color: var(--terracotta); font-size: 1.5rem; }
.btn-quiet {
  background: none;
  border: none;
  color: var(--ink-2);
  text-decoration: underline;
  text-underline-offset: 3px;
  font-size: 1.05rem;
  font-weight: 600;
}
.menu { display: flex; flex-direction: column; gap: 1.1rem; width: 100%; }
.menu-quiet-row { display: flex; gap: 1.5rem; flex-wrap: wrap; justify-content: center; }


/* --- reception menu panel (design: raum-menu) --- */

.menu-panel {
  width: 100%;
  max-width: 430px;
  background: var(--paper-0);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lift);
  padding: 1.3rem 1.2rem;
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
}
.menu-panel-eyebrow {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.menu-panel-lead {
  font-family: var(--font-serif);
  font-style: italic;
  font-size: 1.3rem;
  color: var(--ink-1);
  display: flex;
  align-items: center;
  gap: 0.55rem;
  margin-bottom: 0.2rem;
}
.menu-panel-lead svg {
  flex: none;
  width: 1.35rem;
  height: 1.35rem;
  stroke: var(--terracotta);
  fill: none;
  stroke-width: 2;
}
.menu-row {
  font: inherit;
  font-family: var(--font-serif);
  font-weight: 500;
  font-size: 1.45rem;
  color: var(--ink-0);
  text-align: left;
  display: flex;
  align-items: center;
  gap: 1rem;
  width: 100%;
  padding: 0.75rem 1rem;
  background: #fffdf5;
  border: 1.5px solid var(--paper-4);
  border-bottom-width: 3px;
  border-radius: 14px;
  cursor: pointer;
  touch-action: manipulation;
}
.menu-row:active { transform: translateY(2px); border-bottom-width: 1.5px; }
.menu-row:focus-visible { outline: none; box-shadow: var(--focus); }
.menu-ico {
  flex: none;
  width: 2.6rem;
  height: 2.6rem;
  border-radius: 50%;
  background: rgba(181, 106, 59, 0.14);
  display: grid;
  place-items: center;
  color: var(--terracotta);
}
.menu-ico svg { width: 1.4rem; height: 1.4rem; stroke: currentColor; fill: none; stroke-width: 2; }
.menu-sep { height: 1px; background: var(--paper-4); margin: 0.25rem 0.2rem; }
.menu-row-quiet {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 1.1rem;
  color: var(--ink-2);
  background: none;
  border-color: transparent;
  border-bottom-width: 1.5px;
}
.menu-row-quiet .menu-ico { background: var(--paper-2); color: var(--ink-2); }
.menu-tiny { display: flex; gap: 1rem; justify-content: center; margin-top: 0.1rem; }
.menu-tiny .btn-quiet { font-size: 0.95rem; padding: 0.25rem 0.8rem; }

/* --- off screen: the front door at night (design: raum-tuer) --- */

.door-scene {
  display: flex;
  align-items: center;
  gap: 2rem;
  perspective: 900px;
}
.door-frame {
  position: relative;
  width: min(52vw, 250px);
  aspect-ratio: 250 / 460;
  background: #241a10;
  border-radius: 12px 12px 0 0;
  padding: 12px 12px 0;
  /* porch light above the door */
  box-shadow: 0 -30px 90px rgba(242, 217, 160, 0.14), 0 0 50px rgba(0, 0, 0, 0.4);
}
/* the warm room glimpsed through the open door */
.door-inside {
  position: absolute;
  inset: 12px 12px 0;
  border-radius: 8px 8px 0 0;
  background: linear-gradient(
    var(--room-ceiling) 0 12%,
    var(--room-wall) 12% 76%,
    var(--room-floor) 76% 100%);
}
.door-inside::after {         /* a hint of the green sofa inside */
  content: "";
  position: absolute;
  left: 16%;
  right: 30%;
  bottom: 20%;
  height: 16%;
  border-radius: 8px;
  background: var(--room-sofa);
}
.door-panel {
  position: absolute;
  inset: 12px 12px 0;
  border-radius: 8px 8px 0 0;
  background: linear-gradient(160deg, #96754a, #6f5330);
  box-shadow: inset 0 0 0 3px rgba(0, 0, 0, 0.18);
  transform-origin: left center;
  transition: transform 0.9s var(--ease-soft);
}
.door-panel::before, .door-panel::after {
  content: "";
  position: absolute;
  left: 16%;
  right: 16%;
  border-radius: 6px;
  background: rgba(0, 0, 0, 0.14);
}
.door-panel::before { top: 9%; height: 26%; }
.door-panel::after { top: 44%; height: 38%; }
.door-handle {
  position: absolute;
  right: 9%;
  top: 51%;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: var(--cream);
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4);
  z-index: 1;
}
/* the doorbell IS the power button, with the owner's nameplate */
/* the bell plate: brushed brass with corner screws, a lit porcelain
   button and an engraved name window — like on a real front door */
.door-bell {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.55rem;
  padding: 0.8rem 0.9rem 0.7rem;
  border-radius: 7px;
  background:
    radial-gradient(circle at 7px 7px, #7d6844 1.6px, rgba(0,0,0,0.25) 2.1px, transparent 3.2px),
    radial-gradient(circle at calc(100% - 7px) 7px, #7d6844 1.6px, rgba(0,0,0,0.25) 2.1px, transparent 3.2px),
    radial-gradient(circle at 7px calc(100% - 7px), #7d6844 1.6px, rgba(0,0,0,0.25) 2.1px, transparent 3.2px),
    radial-gradient(circle at calc(100% - 7px) calc(100% - 7px), #7d6844 1.6px, rgba(0,0,0,0.25) 2.1px, transparent 3.2px),
    linear-gradient(160deg, #d6c39a, #b9a274 48%, #a68e60 85%, #b9a274);
  border: 1px solid #6f5b38;
  box-shadow:
    inset 0 1px 1px rgba(255, 246, 220, 0.65),
    inset 0 -2px 3px rgba(60, 42, 14, 0.35),
    0 3px 10px rgba(20, 10, 0, 0.5);
}
#power-button {
  width: 54px;
  height: 54px;
  border-radius: 50%;
  border: none;
  /* brass ring around a warm porcelain button, softly backlit */
  background:
    radial-gradient(circle at 40% 32%, #fffdf4 0%, var(--cream) 45%, #e8d9b4 72%, transparent 73%),
    linear-gradient(155deg, #8a7550, #6f5b38);
  color: var(--terracotta-deep);
  cursor: pointer;
  display: grid;
  place-items: center;
  box-shadow:
    inset 0 1px 2px rgba(255, 250, 230, 0.6),
    0 0 12px rgba(255, 214, 140, 0.55),
    0 2px 4px rgba(30, 18, 0, 0.45);
}
#power-button svg { width: 42%; height: 42%; stroke: currentColor; stroke-width: 2.4; fill: none; }
/* the WHOLE plate rings the bell — a generous target for elderly hands */
#power-button { position: relative; }
#power-button::after { content: ""; position: absolute; inset: -18px -32px -50px; }
#power-button:active { transform: translateY(1px); box-shadow: inset 0 2px 4px rgba(60, 40, 10, 0.4); }
.door-name {
  font-family: var(--font-hand);
  font-weight: 600;
  font-size: 1.15rem;
  line-height: 1.3;
  color: var(--ink-1);
  background: linear-gradient(180deg, #f4ecd6, #eee2c4);
  border: 1px solid #6f5b38;
  border-radius: 3px;
  box-shadow: inset 0 1px 3px rgba(60, 42, 14, 0.35);
  padding: 0.05rem 0.8rem;
  /* sized for the longest documented German name
     ("Ottovordemgentschenfelde", 24 letters = 189px at this font) */
  width: min(12.5rem, 48vw);
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
@media (max-width: 600px) {
  .door-name { width: min(9rem, 40vw); }
}
.off-hint {
  font-family: var(--font-serif);
  font-style: italic;
  color: rgba(245, 234, 208, 0.6);
}
section[data-screen="off"] .error { max-width: 34ch; text-align: center; }

/* One continuous scene: ringing shows the boot progress UNDER the door
   (data-doorboot); when the box is ready the door opens and we walk
   keeps the off-section as a fading overlay) — no cuts. */
/* the progress slot is ALWAYS laid out (visibility, not display), so the
   door never shifts when ringing swaps the hint for the loading bar */
.door-boot { display: flex; visibility: hidden; flex-direction: column; align-items: center; gap: 0.8rem; }
body[data-doorboot] .door-boot { visibility: visible; }
body[data-doorboot] .off-hint { visibility: hidden; }
.door-boot .state-text { color: rgba(245, 234, 208, 0.75); }
.door-boot-bar {
  height: 100%;
  width: 0;
  background: var(--terracotta);
  border-radius: 5px;
  transition: width 0.8s ease;
}

/* --- Der Türspion (design: screen-tuerspion) -------------------------------
   A brass slide in the door: after the ring the slider glides open, two
   warm storybook eyes blink out, glance at the visitor, and the slider
   shuts — then the door opens. Em-scaled: each context sets ONE font-size.
   Pure staging — no face recognition happens at the door. */
#spion {
  position: relative;
  width: 14.8em; height: 5.6em;
  border-radius: 1.2em;
  background: linear-gradient(180deg, #c9a15c, #a97f3e);
  box-shadow: inset 0 0.1em 0 rgba(255, 244, 214, 0.55),
              inset 0 -0.2em 0.3em rgba(26, 18, 8, 0.35),
              0 0.2em 0.6em rgba(26, 18, 8, 0.45);
  overflow: hidden;
}
.spion-slit {
  position: absolute; inset: 0.8em;
  border-radius: 0.8em;
  background: radial-gradient(120% 160% at 50% 35%, #241a10 0%, #1a1208 70%);
  box-shadow: inset 0 0.2em 0.5em rgba(0, 0, 0, 0.75);
  overflow: hidden;
  display: flex; align-items: center; justify-content: center; gap: 1.4em;
}
.spion-slit::after {   /* hallway light spills out once the slider opens */
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(90% 120% at 50% 30%, rgba(242, 217, 160, 0.55), transparent 70%);
  opacity: 0; transition: opacity 0.5s ease;
}
#spion[data-phase="auf"] .spion-slit::after { opacity: 0.35; }
.spion-eye { width: 3.4em; height: 3em; flex: none; }
.spion-eye--r { margin-top: 0.2em; }   /* a hair lower: hand-drawn, not mechanical */
.spion-eye .lider { transform-origin: 50% 50%; transform: scaleY(0.05); }
#spion[data-phase="auf"] .spion-eye .lider { animation: spion-blinzeln 2.6s ease both; }
#spion[data-phase="auf"] .spion-eye .blick { animation: spion-blick 2.6s ease both; }
#spion[data-phase="auf"] .spion-eye--r .lider { animation-delay: 0.06s; }
@keyframes spion-blinzeln {
  0%, 4%    { transform: scaleY(0.05); }
  9%, 30%   { transform: scaleY(1); }
  33%, 35%  { transform: scaleY(0.08); }   /* a short blink */
  38%, 88%  { transform: scaleY(1); }
  94%, 100% { transform: scaleY(0.05); }   /* shut before the slider comes */
}
@keyframes spion-blick {   /* glance: left -> at the visitor -> right -> back */
  0%, 10%   { transform: translateX(-0.35em); }
  26%, 52%  { transform: translateX(0); }
  64%, 78%  { transform: translateX(0.35em); }
  90%, 100% { transform: translateX(0); }
}
.spion-schieber {
  position: absolute; inset: 0.6em;
  border-radius: 0.9em;
  background: linear-gradient(180deg, #96743f, #8a6a3e 55%, #77592f);
  box-shadow: inset 0 0.1em 0 rgba(255, 244, 214, 0.35),
              inset 0 -0.2em 0.2em rgba(26, 18, 8, 0.3),
              0 0.1em 0.3em rgba(26, 18, 8, 0.5);
  transition: transform 0.5s var(--ease-soft);
}
.spion-schieber::after {   /* the thumb groove */
  content: ""; position: absolute; right: 1em; top: 50%;
  width: 0.8em; height: 2.2em; margin-top: -1.1em;
  border-radius: 0.5em;
  background: rgba(26, 18, 8, 0.35);
  box-shadow: inset 0 0.1em 0.2em rgba(0, 0, 0, 0.5);
}
#spion[data-phase="auf"] .spion-schieber { transform: translateX(calc(-100% - 1em)); }
@media (prefers-reduced-motion: reduce) {
  .spion-schieber { transition: none !important; }
  #spion[data-phase="auf"] .spion-eye .lider,
  #spion[data-phase="auf"] .spion-eye .blick { animation: none !important; }
}

@keyframes door-bg-fade { to { opacity: 0; } }
@keyframes walk-in {
  to { transform: scale(2.6) translateY(4%); opacity: 0; }
}
body[data-doorplay="close"] .door-panel {
  animation: door-shut 1s var(--ease-soft) 0.2s backwards;
}
@keyframes door-shut {
  from { transform: rotateY(-82deg); }
  to { transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .door-panel { transition: none !important; animation: none !important; }
  body[data-doorplay="open"] .door-scene { animation: none !important; }
}

/* --- the ring: ambient status (Robject presence) --- */

.ring {
  width: var(--ring-size);
  height: var(--ring-size);
  border-radius: 50%;
  border: 4px solid var(--paper-4);
  position: relative;
  transition: border-color 0.6s ease, box-shadow 0.3s ease;
  box-shadow: 0 0 0 calc(var(--level, 0) * 26px) rgba(181, 106, 59, 0.22);
  animation: breathe 5s ease-in-out infinite;
}
.ring::after {
  content: "";
  position: absolute;
  inset: 14%;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 40%, rgba(201, 168, 119, 0.28), transparent 75%);
}
.ring[data-mode="recording"] { border-color: var(--terracotta); animation: none; }
.ring[data-mode="thinking"] {
  border-style: dashed;
  border-color: var(--moss);
  animation: turn 3.5s linear infinite;
}
.ring[data-mode="speaking"] { border-color: var(--terracotta); animation: breathe 2.2s ease-in-out infinite; }
.ring-boot { border-style: dashed; border-color: var(--moss); animation: turn 3.5s linear infinite; }

@keyframes breathe {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.035); }
}
@keyframes breathe-dark {
  0%, 100% { box-shadow: 0 0 0 0 rgba(245, 234, 208, 0); }
  50% { box-shadow: 0 0 60px 4px rgba(245, 234, 208, 0.08); }
}
@keyframes turn { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .ring, .ring-boot, #power-button { animation: none !important; }
}

.ring-wrap { display: flex; flex-direction: column; align-items: center; gap: 1rem; }

/* --- boot --- */

.boot-track {
  width: min(70vw, 320px);
  height: 10px;
  border-radius: 5px;
  background: var(--paper-3);
  overflow: hidden;
}
#boot-bar {
  height: 100%;
  width: 0;
  background: var(--terracotta);
  border-radius: 5px;
  transition: width 0.8s ease;
}

/* --- dialog --- */

section[data-screen="dialog"] { justify-content: flex-start; gap: 1.6rem; padding-top: 1.4rem; }
.dialog-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem;
  width: 100%;
  min-height: 2.4rem;
}
.dialog-badges { display: flex; gap: 0.6rem; flex: 1; min-width: 0; overflow: hidden; }
.dialog-top { position: relative; z-index: 6; }
.dialog-actions {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  flex: none;
}
.btn-done {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font: inherit;
  font-size: 1rem;
  font-weight: 700;
  cursor: pointer;
  white-space: nowrap;
  padding: 0.5rem 1.1rem;
  border-radius: 999px;
  border: none;
  background: var(--terracotta);
  color: var(--cream);
  box-shadow: 0 3px 10px rgba(60, 40, 15, 0.22);
}
.btn-done svg { width: 1.15rem; height: 1.15rem; stroke: currentColor; stroke-width: 2.4; }
.btn-done:focus-visible { outline: none; box-shadow: var(--focus); }
.dialog-cancel {
  background: transparent;
  border: none;
  border-radius: 999px;
  color: var(--ink-2);
  font: inherit;
  font-size: 0.95rem;
  font-weight: 600;
  cursor: pointer;
  flex: none;
  padding: 0.5rem 0.8rem;
  white-space: nowrap;
}
.dialog-cancel:hover { color: var(--ink-0); }
.dialog-cancel:focus-visible { outline: none; box-shadow: var(--focus); border-radius: 8px; }
.badge {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--terracotta-deep);
  border: 1.5px solid var(--terracotta);
  border-radius: 999px;
  padding: 0.3rem 0.9rem;
  background: rgba(181, 106, 59, 0.08);
  /* a long object name truncates instead of wrapping into / over the
     cancel button */
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.badge:empty { display: none; }
.dialog-cancel { flex: none; }
.badge-object { color: var(--ink-1); border-color: var(--moss); background: rgba(106, 122, 58, 0.1); }

/* --- the chat thread: box left, person right, like the AI chats ------- */
.chat-scroll {
  width: 100%;
  flex: 1 1 auto;
  min-height: 6rem;
  overflow-y: auto;
  scrollbar-width: thin;
}
.chat-thread {
  list-style: none;
  margin: 0;
  padding: 0.2rem 0.1rem 0.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
}
.bubble {
  max-width: 74%;
  padding: 0.6rem 0.95rem;
  border-radius: 18px;
  font-size: var(--fs-base);
  line-height: 1.4;
}
.bubble p { margin: 0; overflow-wrap: anywhere; }
.bubble-label {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.06em;
  color: var(--ink-2);
  margin-bottom: 0.15rem;
}
.bubble-user {
  align-self: flex-end;
  background: var(--cream);
  border: none;
  border-bottom-right-radius: 6px;
  color: var(--ink-0);
  text-align: left;
  box-shadow: 0 1px 3px rgba(60, 40, 20, 0.12);
}
.bubble-box {
  align-self: flex-start;
  background: var(--paper-0);
  border: 1px solid rgba(60, 40, 20, 0.12);
  border-bottom-left-radius: 6px;
  color: var(--ink-0);
  text-align: left;
  box-shadow: 0 1px 3px rgba(60, 40, 20, 0.08);
}
.bubble-thinking { display: flex; gap: 0.35rem; padding: 0.85rem 1rem; }
.bubble-thinking span {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--ink-2);
  opacity: 0.4;
  animation: bubble-dot 1.2s infinite;
}
.bubble-thinking span:nth-child(2) { animation-delay: 0.2s; }
.bubble-thinking span:nth-child(3) { animation-delay: 0.4s; }
@keyframes bubble-dot {
  0%, 60%, 100% { opacity: 0.35; transform: translateY(0); }
  30% { opacity: 1; transform: translateY(-3px); }
}

/* the composer: one rounded container, tools inside — the AI-chat shape */
#chat-input-row {
  position: absolute;
  left: 1rem;
  right: 1rem;
  bottom: 100%;
  margin-bottom: 0.7rem;
  display: flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.35rem 0.4rem;
  background: var(--paper-0);
  border: 1.5px solid var(--paper-4);
  border-radius: 999px;
  box-shadow: 0 6px 18px rgba(60, 40, 20, 0.14);
  pointer-events: auto;
}
#chat-input-row[hidden] { display: none; }
#chat-input-row:focus-within { box-shadow: 0 6px 18px rgba(60, 40, 20, 0.14), var(--focus); }
.chat-tool, #chat-send {
  flex: none;
  width: 44px;
  height: 44px;
  border: none;
  border-radius: 50%;
  display: grid;
  place-items: center;
  cursor: pointer;
  background: transparent;
  color: var(--ink-1);
}
.chat-tool svg, #chat-send svg {
  width: 22px;
  height: 22px;
  stroke: currentColor;
  stroke-width: 2;
  fill: none;
}
.chat-tool:hover { background: rgba(60, 40, 20, 0.06); }
.chat-tool:disabled, #chat-send:disabled { opacity: 0.4; cursor: default; }
#chat-send { background: var(--terracotta); color: #fff; }
#chat-text {
  flex: 1;
  min-width: 0;
  border: none;
  background: transparent;
  font: inherit;
  font-size: var(--fs-base);
  color: var(--ink-0);
  padding: 0.4rem 0.2rem;
}
#chat-text:focus-visible { outline: none; }


/* --- shared voice controls --- */

.controls {
  display: none;
  /* the bar itself must never swallow clicks meant for chips beneath it
     (it killed the back button at the walls) — only its children are live */
  pointer-events: none;
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  align-items: flex-end;
  justify-content: center;
  gap: 1.2rem;
  max-width: 640px;
  margin: 0 auto;
  /* clear the iPhone home indicator */
  padding: 0.6rem 1.5rem calc(1.2rem + env(safe-area-inset-bottom));
}
body[data-screen="main_menu"] .controls,
body[data-screen="dialog"] .controls { display: flex; }
body[data-screen="main_menu"] .btn-side { visibility: hidden; }
body[data-screen="dialog"] .controls::before {
  content: "";
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: 0;
  width: min(660px, 94vw);
  height: 5.6rem;
  background: rgba(246, 239, 217, 0.94);
  border: 1.5px solid var(--paper-4);
  border-bottom: none;
  border-radius: 20px 20px 0 0;
  box-shadow: 0 -6px 22px rgba(60, 40, 15, 0.22);
}
.controls > * { position: relative; pointer-events: auto; }

.btn-side {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.35rem;
  font-size: 1rem;
  font-weight: 600;
  padding: 0.6rem 0.9rem 0.55rem;
  min-width: 6.6rem;
  background: var(--paper-0);
  border: 1.5px solid var(--paper-4);
  border-bottom-width: 3px;
  border-radius: 14px;
  color: var(--ink-1);
  cursor: pointer;
  box-shadow: 0 3px 10px rgba(60, 40, 15, 0.16);
}
.btn-side:hover { background: var(--paper-1); }
.btn-side svg {
  width: 2.1rem;
  height: 2.1rem;
  padding: 0.4rem;
  box-sizing: content-box;
  border-radius: 50%;
  background: rgba(181, 106, 59, 0.14);
  stroke: var(--terracotta-deep);
  stroke-width: 1.8;
  fill: none;
}

.ptt {
  width: var(--ptt-size);
  height: var(--ptt-size);
  border-radius: 50%;
  border: 3px solid var(--terracotta-deep);
  background: radial-gradient(circle at 38% 30%, #c97f4e, var(--terracotta) 60%);
  color: var(--cream);
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  touch-action: none;
  -webkit-user-select: none;
  user-select: none;
  box-shadow: 0 4px 0 var(--terracotta-deep), var(--shadow-card);
}
.ptt svg { width: 2.6rem; height: 2.6rem; stroke: currentColor; fill: currentColor; stroke-width: 1; }
/* while recording the mic becomes a stop square — on phones that reads
   as "tap again to finish" */
.ptt .ptt-ico-stop { display: none; }
.ptt[data-active] .ptt-ico-stop { display: block; }
.ptt[data-active] .ptt-ico-mic { display: none; }
.ptt-label { font-size: 1rem; line-height: 1.25; text-align: center; font-weight: 600; }
/* children must never become pointer targets: an initial touch landing on
   the icon could be gesture-cancelled and end the recording mid-hold */
.ptt svg, .ptt span, .ptt .ptt-label { pointer-events: none; }
.ptt:active { transform: scale(0.96); }
.ptt[data-active] {
  background: radial-gradient(circle at 38% 30%, #a2602f, var(--terracotta-deep) 65%);
  box-shadow: 0 0 0 calc(var(--level, 0) * 22px + 6px) rgba(181, 106, 59, 0.3);
  transform: scale(1.04);
}
.ptt:disabled { opacity: 0.45; cursor: default; }

/* --- memories: the cork pinboard (Fotowand) --- */

body[data-screen="memories"] .greeting,
body[data-screen="people"] .greeting {
  color: var(--paper-1);
  text-shadow: 0 2px 8px rgba(40, 20, 5, 0.55);
}
body[data-screen="people"] #people-back { box-shadow: 0 6px 18px rgba(20, 10, 0, 0.4); }

/* --- the whiteboard sheet (mobile: card; desktop: lives on the wall) --- */
#wb-sheet {
  background: #fdfaf2;
  border-radius: 6px;
  box-shadow: inset 0 0 30px rgba(120, 90, 40, 0.08);
  width: min(92vw, 520px);
}
#wb-sheet svg { display: block; width: 100%; height: auto; }
#mv-graph-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0.7rem auto 0;
}
#mv-graph-btn[hidden] { display: none; }
#mv-graph-btn svg {
  width: 1.35rem;
  height: 1.35rem;
  stroke: currentColor;
  stroke-width: 1.8;
  fill: none;
}
.person-memories { display: flex; flex-direction: column; gap: 0.4rem; }
.person-mem-link {
  font: inherit;
  font-family: var(--font-hand);
  font-weight: 500;
  font-size: 1.2rem;
  text-align: left;
  background: none;
  border: none;
  color: var(--terracotta-deep);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
  padding: 0.1rem 0;
}
.pinboard {
  width: 100%;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 1.6rem 1.2rem;
  padding: 0.8rem 0.2rem 1.2rem;
  align-items: start;
}
.polaroid {
  font: inherit;
  border: none;
  background: #f7eccf;
  padding: 8px 8px 1.4rem;   /* thick bottom = real polaroid */
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.35);
  cursor: pointer;
  position: relative;
  text-align: center;
  transition: transform 0.25s, box-shadow 0.25s;
}
.polaroid:nth-child(2n)   { background: #fff6dd; }
.polaroid:nth-child(4n+1) { transform: rotate(-4deg); }
.polaroid:nth-child(4n+2) { transform: rotate(3deg); }
.polaroid:nth-child(4n+3) { transform: rotate(-2deg); }
.polaroid:nth-child(4n)   { transform: rotate(5deg); }
.polaroid:hover, .polaroid:focus-visible {
  transform: rotate(0deg) translateY(-6px) scale(1.04);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.5);
  z-index: 3;
}
.polaroid img,
.polaroid .photo-placeholder {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  display: block;
  border-radius: 2px;
}
/* sepia striped placeholder for memories without an object photo */
.polaroid .photo-placeholder {
  background: repeating-linear-gradient(135deg, var(--sepia-1) 0 14px, var(--sepia-2) 14px 28px);
  position: relative;
  display: grid;
  place-items: center;
}
.polaroid .photo-placeholder::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse at 30% 20%, rgba(255, 240, 200, 0.4), transparent 50%),
    radial-gradient(ellipse at 80% 80%, rgba(40, 20, 5, 0.3), transparent 60%);
  pointer-events: none;
}
.polaroid .photo-placeholder span {
  font-family: var(--font-hand);
  font-weight: 600;
  font-size: 3rem;
  color: rgba(40, 25, 10, 0.6);
  z-index: 1;
}
.polaroid figcaption {
  font-family: var(--font-hand);
  font-weight: 500;
  font-size: 1.35rem;
  line-height: 1.05;
  color: var(--ink-1);
  padding-top: 0.5rem;
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.polaroid .frame-date {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-2);
  margin-top: 0.25rem;
}
/* thumbtack */
.polaroid::before {
  content: "";
  position: absolute;
  top: -9px;
  left: 50%;
  transform: translateX(-50%);
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #f25a3a 0%, #a02818 60%, #5a1408 100%);
  box-shadow: inset 0 -3px 4px rgba(40, 5, 0, 0.6), inset 0 2px 3px rgba(255, 180, 150, 0.5), 0 3px 6px rgba(0, 0, 0, 0.4);
  z-index: 5;
}
/* sticky note (empty board, toasts) */
.sticky-note {
  background: #fef4a8;
  font-family: var(--font-hand);
  font-weight: 500;
  font-size: 1.5rem;
  line-height: 1.2;
  color: var(--ink-0);
  padding: 1rem 1.4rem;
  transform: rotate(-2deg);
  box-shadow: 0 4px 10px rgba(0, 0, 0, 0.25);
  position: relative;
  max-width: 34ch;
  text-align: center;
  grid-column: 1 / -1;
  justify-self: center;
}
.sticky-note::before {
  content: "";
  position: absolute;
  top: -8px;
  left: 50%;
  transform: translateX(-50%) rotate(-3deg);
  width: 64px;
  height: 18px;
  background: linear-gradient(90deg, rgba(240, 210, 140, 0) 0%, rgba(240, 210, 140, 0.85) 10%, rgba(240, 210, 140, 0.85) 90%, rgba(240, 210, 140, 0) 100%);
  box-shadow: 0 2px 4px rgba(60, 40, 20, 0.15);
}

.memories-list { display: flex; flex-direction: column; gap: 0.9rem; width: 100%; }
.memory-card {
  background: var(--paper-0);
  border: 1.5px solid var(--paper-4);
  border-bottom-width: 3px;
  border-radius: var(--radius);
  padding: 1rem 1.3rem;
  text-align: left;
  font: inherit;
  width: 100%;
  box-shadow: var(--shadow-card);
}
.memory-card h3 { font-family: var(--font-serif); font-weight: 600; font-size: 1.3rem; margin-bottom: 0.15rem; }
.memory-card p { color: var(--ink-2); font-size: 1rem; }
.memory-meta {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.memory-transcript { white-space: pre-wrap; color: var(--ink-1); font-size: 1.05rem; margin-top: 0.5rem; }
.memories-empty { color: var(--ink-2); text-align: center; }

body[data-screen="memories"] #memories-back {
  box-shadow: 0 6px 18px rgba(20, 10, 0, 0.4);
}

/* --- memory viewer: flip card --- */

#memory-viewer {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.2rem;
  padding: 1.5rem;
  /* solid tint, no backdrop-filter: a live blur behind a 3D transform
     re-composites every frame and makes the flip stutter */
  background: rgba(26, 18, 8, 0.9);
}
#memory-viewer[hidden] { display: none; }

/* hero-zoom layer: the card grows from the tapped thumbnail (set in JS) */
#zoom-wrap {
  width: min(82vw, 360px);
  will-change: transform;
}
/* perspective must live on the PARENT of the rotating element, otherwise
   the flip renders flat */
.flip {
  width: 100%;
  perspective: 1500px;
  cursor: pointer;
}
#memory-card {
  position: relative;
  width: 100%;
  transform-style: preserve-3d;
  transition: transform 0.55s cubic-bezier(0.45, 0.05, 0.2, 1);
  will-change: transform;
}
#memory-card.flipped { transform: rotateY(180deg); }
@media (prefers-reduced-motion: reduce) {
  #memory-card, #zoom-wrap { transition: none !important; }
}
.flip-face {
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
}
/* the front sits in normal flow and sizes the card; the back overlays it,
   so both faces share the exact same box and the flip stays rock-steady */
.flip-front {
  position: relative;
  /* an explicit identity 3D transform forces the browser to treat the
     front as a real 3D layer, so its backface is culled when the card is
     turned — without it some browsers keep painting the mirrored photo
     tilting behind the text */
  transform: rotateY(0deg);
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}
.flip-back {
  position: absolute;
  inset: 0;
  transform: rotateY(180deg);
  /* no overflow here — it would break backface-visibility in Firefox */
  background:
    radial-gradient(ellipse at 25% 15%, rgba(255, 255, 255, 0.5), transparent 60%),
    var(--paper-0);
  border-radius: 4px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);
}
/* the scrollable text panel on the back (date, summary, full dialog) */
.back-scroll {
  height: 100%;
  overflow-y: auto;
  padding: 1.4rem;
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  border-radius: 4px;
}

/* front: the enlarged polaroid — the whole photo at its TRUE aspect ratio
   (never cropped or stretched), bounded so it can't fill the screen */
.polaroid.polaroid-big,
.polaroid.polaroid-big:hover {
  /* beat the pinboard nth-child tilt rules (same specificity, later wins) */
  transform: none;
}
.polaroid-big {
  background: #f7eccf;
  padding: 14px 14px 2rem;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);
  display: flex;
  flex-direction: column;
}
.polaroid-big::before { display: none; } /* no thumbtack on the big card */
/* enlarged photo: the same square crop as the pinned polaroid (WYSIWYG) */
.polaroid-big #mv-photo { display: block; width: 100%; aspect-ratio: 1; }
.polaroid-big #mv-photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 2px;
}
.polaroid-big #mv-photo .photo-placeholder {
  width: 100%;
  aspect-ratio: 1;       /* memories without a photo: a square sepia card */
  background: repeating-linear-gradient(135deg, var(--sepia-1) 0 18px, var(--sepia-2) 18px 36px);
  display: grid;
  place-items: center;
  position: relative;
  border-radius: 2px;
}
.polaroid-big #mv-photo .photo-placeholder span {
  font-family: var(--font-hand);
  font-weight: 600;
  font-size: 5rem;
  color: rgba(40, 25, 10, 0.6);
}
.polaroid-big figcaption {
  font-family: var(--font-hand);
  font-weight: 600;
  font-size: 1.7rem;
  line-height: 1.05;
  color: var(--ink-1);
  padding-top: 0.6rem;
  text-align: center;
}
.flip-back h2 { font-family: var(--font-serif); font-weight: 600; font-size: 1.6rem; color: var(--ink-0); }
#mv-summary { color: var(--ink-1); font-size: 1.1rem; }
.dialog-log {
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  margin-top: 0.4rem;
  border-top: 1px dashed var(--paper-4);
  padding-top: 0.9rem;
}
.dialog-line { display: flex; flex-direction: column; gap: 0.15rem; }
.dialog-who {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.dialog-text {
  font-size: 1.05rem;
  line-height: 1.35;
  padding: 0.5rem 0.8rem;
  border-radius: 12px;
  background: var(--paper-2);
  color: var(--ink-0);
}
.dialog-line.box { align-items: flex-start; }
.dialog-line.box .dialog-text { background: rgba(181, 106, 59, 0.14); }
.dialog-line.person { align-items: flex-end; }
.dialog-line.person .dialog-text {
  background: rgba(106, 122, 58, 0.14);
  font-family: var(--font-hand);
  font-weight: 500;
  font-size: 1.25rem;
}
.mv-entities {
  font-family: var(--font-hand);
  font-weight: 500;
  font-size: 1.25rem;
  color: var(--terracotta-deep);
}
.mv-delete {
  align-self: center;
  margin-top: 0.4rem;
  font-size: 1rem;
  color: #a02818;
  border-color: rgba(160, 40, 24, 0.4);
  background: rgba(160, 40, 24, 0.06);
}
.flip-hint {
  text-align: center;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.flip-back .flip-hint { color: var(--ink-2); }
#memory-viewer-close { min-width: 12rem; }

/* --- camera overlay --- */

#camera-overlay, #ob-face-overlay {
  position: fixed;
  inset: 0;
  background: radial-gradient(ellipse at 50% 60%, var(--night-2) 0%, var(--night-1) 70%, var(--night-0) 100%);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.2rem;
  padding: 1.5rem;
  z-index: 20;
}
#camera-overlay[hidden], #ob-face-overlay[hidden] { display: none; }
/* Live cameras are framed like a polaroid and SQUARE (object-fit: cover),
   so the live view already shows exactly the square that gets captured. */
#camera-video, #ob-face-video {
  width: min(82vw, 360px);
  aspect-ratio: 1;
  object-fit: cover;
  background: #000;
  border: 12px solid #f7eccf;      /* polaroid frame */
  border-bottom-width: 2.2rem;
  border-radius: 3px;
  box-shadow: 0 18px 44px rgba(0, 0, 0, 0.5);
}
#ob-face-video { transform: scaleX(-1); } /* mirror: natural self-view */
#camera-video[hidden], #ob-face-video[hidden] { display: none; }

/* the captured still, shown as a polaroid like on the walls (square) */
#ob-face-preview { width: min(72vw, 320px); }
#ob-face-preview[hidden] { display: none; }
#ob-face-preview #ob-face-still { width: 100%; aspect-ratio: 1; }
#ob-face-preview #ob-face-still img {
  width: 100%; height: 100%; object-fit: cover;
  border-radius: 2px; display: block;
}
.face-hint { color: rgba(245, 234, 208, 0.7); font-family: var(--font-serif); font-style: italic; }

/* the frozen object shot, presented as a polaroid (square) */
.camera-polaroid {
  width: min(82vw, 360px);
  cursor: default;
}
.camera-polaroid[hidden] { display: none; }
.camera-polaroid:hover { transform: none; box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55); }
.camera-polaroid img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: 2px;
  display: block;
}
.camera-actions { margin-top: 0.4rem; }
.row { display: flex; gap: 0.9rem; justify-content: center; flex-wrap: wrap; }
#register-panel {
  background: var(--paper-0);
  border-radius: var(--radius);
  padding: 1.4rem;
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  text-align: center;
  width: min(92vw, 480px);
  box-shadow: var(--shadow-lift);
}
#register-panel[hidden] { display: none; }

/* --- feedback --- */

.error { color: #a02818; }
#toast {
  position: fixed;
  bottom: calc(1.2rem + env(safe-area-inset-bottom));
  left: 50%;
  transform: translateX(-50%) rotate(-1deg);
  background: #fef4a8;
  color: var(--ink-0);
  font-family: var(--font-hand);
  font-weight: 500;
  font-size: 1.35rem;
  line-height: 1.2;
  padding: 0.8rem 1.5rem;
  box-shadow: 0 6px 16px rgba(40, 20, 5, 0.35);
  z-index: 30;
  max-width: 90vw;
  text-align: center;
}
#toast[hidden] { display: none; }
/* on the screens with the voice dock, the toast sits ABOVE it so it can
   never cover the record button */
body[data-screen="main_menu"] #toast,
body[data-screen="dialog"] #toast {
  bottom: calc(var(--dock-h) + env(safe-area-inset-bottom) + 0.75rem);
}

/* the phone's roll-down canvas + framed boards exist only below 900px */
#mobile-leinwand, .mobile-board { display: none; }

/* ===================================================================
   Mobil: die Wohnung im Hochformat (design/preview, Jul 2026).
   Every camera position of the room becomes ONE portrait screen; the
   talk button follows the family-chat pattern (hold-to-talk FAB in the
   right thumb arc); the furniture keeps its look without the 3D room.
   =================================================================== */
/* Applied whenever the effective view is 2d — JS guarantees that on
   every viewport below 900px, and on wide screens when the person
   chose the flat view via the gear menu. */
/* --- safe centering: a fixed section that centers content taller than
       the viewport clips it top AND bottom. On phones every screen may
       scroll; the auto margins centre the content only when it fits --- */
body[data-view="2d"] .screen {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  justify-content: flex-start;
  padding-top: calc(1rem + env(safe-area-inset-top));
}
body[data-view="2d"] .screen:not(.screen-scroll) > :first-child { margin-top: auto; }
body[data-view="2d"] .screen:not(.screen-scroll) > :last-child { margin-bottom: auto; }

/* --- Klingel statt Tür: no room here, so no door — the brass plate
       alone wakes the box, EXACTLY centered like a nameplate in the
       dark. The hint and the boot bar live in a bottom zone, so they
       can never push the plate off centre --- */
body[data-view="2d"] .door-frame { display: none; }
body[data-view="2d"] .door-scene {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  pointer-events: none;
}
body[data-view="2d"] .door-scene .door-bell { pointer-events: auto; }
/* no door on the phone: the peephole floats as a small hatch in the dark
   above the bell — only while its act runs (right at the end of loading,
   just before the room opens) */
body[data-view="2d"] #spion {
  position: absolute;
  left: 50%;
  top: 20%;
  transform: translateX(-50%);
  font-size: 9px;
  opacity: 0;
  transition: opacity 0.6s ease;
  pointer-events: none;
}
body[data-view="2d"][data-spion] #spion { opacity: 1; }
body[data-view="2d"] section[data-screen="off"] .off-hint, body[data-view="2d"] section[data-screen="off"] .door-boot, body[data-view="2d"] section[data-screen="off"] .error {
  position: absolute;
  left: 1.5rem;
  right: 1.5rem;
  margin: 0;
  text-align: center;
}
body[data-view="2d"] section[data-screen="off"] .off-hint { bottom: calc(14% + env(safe-area-inset-bottom)); }
body[data-view="2d"] section[data-screen="off"] .door-boot { bottom: calc(7% + env(safe-area-inset-bottom)); }
body[data-view="2d"] section[data-screen="off"] .error { bottom: calc(2% + env(safe-area-inset-bottom)); max-width: none; }
body[data-view="2d"] .door-bell { padding: 1.6rem 2rem 1.4rem; gap: 1rem; border-radius: 10px; }
body[data-view="2d"] #power-button { width: 96px; height: 96px; }
body[data-view="2d"] .door-name { font-size: 1.6rem; width: min(15rem, 64vw); }

/* --- Sprechen wohnt unten rechts (WhatsApp-Muster) --- */
body[data-view="2d"] { --dock-h: 142px; }
body[data-view="2d"] .controls {
  justify-content: flex-start;
  align-items: center;
  gap: 0.6rem;
  max-width: none;
  padding: 0.5rem 7.4rem calc(1.1rem + env(safe-area-inset-bottom)) 1rem;
}
body[data-view="2d"][data-screen="dialog"] .controls::before { display: none; }
body[data-view="2d"] .ptt {
  position: absolute;
  right: calc(1.1rem + env(safe-area-inset-right));
  /* well clear of Safari's bottom toolbar and the home-indicator swipe
     zone — touches down there get stolen or cancelled mid-hold */
  bottom: calc(2.75rem + env(safe-area-inset-bottom));
  width: 84px;
  height: 84px;
  box-shadow: 0 4px 0 var(--terracotta-deep), 0 10px 26px rgba(60, 40, 20, 0.35);
  -webkit-touch-callout: none;
}
body[data-view="2d"] .ptt svg { width: 2.2rem; height: 2.2rem; }
body[data-view="2d"] .ptt .ptt-label { display: none; }

/* quiet ways as paper chips in the left thumb arc */
body[data-view="2d"] .controls .btn-side {
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  gap: 0.45rem;
  min-height: 52px;
  min-width: 0;
  width: auto;
  padding: 0.55rem 1rem;
  border: none;
  border-radius: 999px;
  background: var(--paper-0);
  box-shadow: 0 3px 10px rgba(60, 40, 20, 0.25);
  font-size: 1rem;
  font-weight: 700;
  color: var(--ink-1);
  white-space: nowrap;
}
body[data-view="2d"] .controls .btn-side svg { width: 1.2rem; height: 1.2rem; }
body[data-view="2d"] .controls .btn-side span { display: inline; }

/* --- Dialog: the FAB carries the state, the ring retires; the
       Leinwand rolls down for the projected photo --- */
body[data-view="2d"][data-screen="dialog"] #ring { display: none; }
/* Abbrechen sits quietly top right, like on the design card */
/* the actions ride in the header now; give the badges room from the gear */
body[data-view="2d"] section[data-screen="dialog"] .dialog-top {
  padding-right: calc(52px + 1.4rem);   /* clear of the fixed view gear */
}
/* badges leave room for it */

body[data-view="2d"] #mobile-leinwand {
  display: block;
  width: min(84vw, 420px);
  align-self: center;
  margin: 0 auto;
  max-height: 0;
  overflow: hidden;
  transition: max-height 1.6s cubic-bezier(0.3, 0, 0.7, 1);
}
body[data-view="2d"] #mobile-leinwand.down { max-height: 240px; }
body[data-view="2d"] .ml-sheet {
  background: #fdfaf2;
  border-radius: 0 0 2px 2px;
  box-shadow: 0 10px 26px rgba(40, 25, 10, 0.35);
  padding: 6px;
}
body[data-view="2d"] .ml-sheet img {
  display: block;
  width: 100%;
  height: 150px;
  background: #efe6cf;   /* calm placeholder while the photo loads */
  object-fit: cover;
  filter: sepia(0.22) saturate(0.85) brightness(1.06);
}
body[data-view="2d"] .ml-bar {
  width: calc(100% + 14px);
  margin: 2px 0 0 -7px;
  height: 10px;
  border-radius: 5px;
  background: linear-gradient(180deg, var(--room-wood), #6e5430);
  box-shadow: 0 2px 6px rgba(40, 25, 10, 0.35);
}

/* --- Pinnwände: the framed cork boards from the living room, 1:1,
       garland hanging over the top edge; the wall itself is paper --- */
body[data-view="2d"][data-screen="memories"], body[data-view="2d"][data-screen="people"] {
  background:
    radial-gradient(ellipse at 20% 10%, rgba(255, 255, 255, 0.6), transparent 60%),
    repeating-linear-gradient(0deg, rgba(120, 90, 40, 0.025) 0 1px, transparent 1px 3px),
    var(--paper-1);
}
body[data-view="2d"][data-screen="memories"] .greeting, body[data-view="2d"][data-screen="people"] .greeting {
  color: var(--ink-0);
  text-shadow: none;
}
body[data-view="2d"] .mobile-board {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  margin-top: 1.4rem;
  border: 12px solid var(--room-wood);
  border-radius: 6px;
  box-shadow:
    inset 0 0 0 2px rgba(60, 35, 10, 0.35),
    inset 0 3px 10px rgba(40, 20, 5, 0.35),
    0 10px 30px rgba(60, 40, 20, 0.30);
  padding: 2.1rem 0.55rem 0.8rem;
  background:
    radial-gradient(ellipse at 30% 18%, rgba(255, 235, 190, 0.30), transparent 65%),
    repeating-radial-gradient(circle at 20% 30%, rgba(80, 40, 10, 0.10) 0 2px, transparent 2px 7px),
    #c1935a;
}
body[data-view="2d"] .mb-garland {
  position: absolute;
  top: -18px;
  left: 4%;
  width: 92%;
  height: auto;
  z-index: 2;
}

/* --- Whiteboard: back chip top left, FAB stays --- */
body[data-view="2d"][data-screen="memories"] .controls,
body[data-view="2d"][data-screen="people"] .controls,
body[data-view="2d"][data-screen="graph"] .controls { display: flex; }
body[data-view="2d"][data-screen="memories"] .btn-side,
body[data-view="2d"][data-screen="people"] .btn-side,
body[data-view="2d"][data-screen="graph"] .btn-side { visibility: hidden; }
body[data-view="2d"] #graph-back {
  order: -1;
  align-self: flex-start;
  width: auto;
  min-height: 52px;
  padding: 0.55rem 1.2rem;
  border-radius: 999px;
  font-size: 1.05rem;
  box-shadow: 0 3px 10px rgba(60, 40, 20, 0.25);
}
body[data-view="2d"] section[data-screen="graph"] .greeting { font-size: 1.7rem; }

/* --- toasts live at the top, clear of the talk button --- */
body[data-view="2d"] #toast, body[data-view="2d"][data-screen="main_menu"] #toast, body[data-view="2d"][data-screen="dialog"] #toast {
  top: calc(0.9rem + env(safe-area-inset-top));
  bottom: auto;
}

#build-tag {
  position: fixed;
  bottom: 4px;
  right: 8px;
  font-family: var(--font-mono);
  font-size: 0.65rem;
  color: rgba(130, 110, 80, 0.55);
  z-index: 5;
}

@media (max-height: 640px) {
  :root { --ring-size: 150px; --fs-display: 1.9rem; --fs-big: 1.45rem; }
}

/* --- narrow phones (portrait): keep the dialog footer from overflowing
   and give type a touch less room --- */
@media (max-width: 480px) {
  :root {
    --fs-display: 2rem;
    --fs-big: 1.5rem;
    --fs-base: 1.25rem;
    --ring-size: min(54vw, 210px);
    /* smaller record button on phones — the dock height, footer padding and
       toast offset all follow from this automatically */
    --ptt-size: min(33vw, 150px);
  }
  .screen { padding-left: 1rem; padding-right: 1rem; }
  .btn-big { font-size: 1.4rem; padding: 1.15rem 1.2rem; }

  /* scoped like the 2d block above, or the raised specificity there would
     win the tie it used to lose by source order (narrow phones are always
     effective-view 2d, so this changes nothing visually) */
  body[data-view="2d"] .controls { gap: 0.5rem; padding: 0.5rem 0.6rem calc(0.8rem + env(safe-area-inset-bottom)); }
  .ptt-label { font-size: 0.9rem; }
  .btn-side { min-width: 4.4rem; font-size: 0.9rem; padding: 0.5rem 0.2rem; }
  .btn-side svg { width: 1.9rem; height: 1.9rem; }

  /* two portraits per row on the walls */
  .pinboard { grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 1.2rem 0.9rem; }
  .dialog-cancel { font-size: 1rem; }
}

/* very small / older phones */
@media (max-width: 360px) {
  :root { --fs-base: 1.15rem; --fs-big: 1.35rem; }
  .btn-side span { display: none; } /* icon-only side buttons to save width */
  .btn-side { min-width: 3.4rem; }
}

/* ==========================================================================
   The room in pseudo-3D (desktop): a CSS-3D stage of flat planes — floor,
   ceiling, back wall (sofa, table, canvas + projector), window wall left,
   right wall with the two REAL boards. Every screen is a camera standpoint;
   app.js composes ONE transform per pose (updateCameraPoses) — real
   parallax between the planes. Rule for this audience: perspective for
   ambience, FRONTAL for content — at the wall poses the right wall lies in
   the picture plane at scale 1, so the grids render at their real pixel
   size and are never read or tapped at a skew. Phones keep the plain
   screens (>= 900px only).
   ========================================================================== */

#room { display: none; }
/* today's coffee-table set: app.js puts data-tisch on #room */
#room g[data-tisch] { visibility: hidden; }
#room[data-tisch="kaffee"] g[data-tisch="kaffee"],
#room[data-tisch="tee"] g[data-tisch="tee"],
#room[data-tisch="kuchen"] g[data-tisch="kuchen"] { visibility: visible; }

/* The projector (app.js sets data-projecting while a memory with a photo
   is being talked about): the canvas rolls down from its cassette, then
   the beam and the projected photo fade in. */
/* motorised canvas: the SHEET unrolls while the pull BAR rides its
   bottom edge down (it used to squash with the scale). Off: the beam
   dies first, then the motor reels the canvas back up. */
#room .rm-canvas-sheet {
  transform-box: fill-box;
  transform-origin: top center;
  transform: scaleY(0.02);           /* a sliver of cloth peeks from the rail */
  transition: transform 1.6s cubic-bezier(0.3, 0, 0.7, 1) 0.25s;
}
#room .rm-canvas-bar {
  transform: translateY(-404px);
  transition: transform 1.6s cubic-bezier(0.3, 0, 0.7, 1) 0.25s;
}
#room[data-projecting="1"] .rm-canvas-sheet {
  transform: scaleY(1);
  transition: transform 1.6s cubic-bezier(0.3, 0, 0.7, 1);
}
#room[data-projecting="1"] .rm-canvas-bar {
  transform: translateY(0);
  transition: transform 1.6s cubic-bezier(0.3, 0, 0.7, 1);
}
#room .rm-beam { opacity: 0; transition: opacity 0.3s ease; }
#room[data-projecting="1"] .rm-beam {
  opacity: 0.55;
  transition: opacity 0.45s ease 1.75s;   /* once the canvas has landed */
}
#room-canvas { opacity: 0; transition: opacity 0.3s ease; }
#room[data-projecting="1"] #room-canvas {
  opacity: 1;
  transition: opacity 0.5s ease 1.85s;
}

/* overlays settle in softly over the standing room (all viewports) */
#memory-viewer:not([hidden]),
#camera-overlay:not([hidden]),
#ob-face-overlay:not([hidden]) { animation: overlay-in 0.3s ease; }
@keyframes overlay-in { from { opacity: 0; } }

@media (min-width: 900px) {
  body[data-view="3d"][data-screen="off"] #room, body[data-view="3d"][data-screen="main_menu"] #room, body[data-view="3d"][data-screen="dialog"] #room, body[data-view="3d"][data-screen="memories"] #room, body[data-view="3d"][data-screen="people"] #room, body[data-view="3d"][data-screen="graph"] #room {
    display: block;
    position: fixed;
    inset: 0;
    overflow: hidden;
    background: var(--room-ceiling);
    perspective: var(--r3-p, 2300px);
    perspective-origin: 50% 44%;
  }

  /* The stage: the back wall's rectangle spans it; the other planes fold
     out of it. One unit u (--r3-u, app.js) is chosen so the wall poses
     render 1:1. Camera poses are complete transform strings from app.js —
     identical structure everywhere, so moves interpolate as one swing. */
  /* the active camera pose lives in one variable so BOTH stages (the room
     and the entry wall, which rides the same camera at its own depth)
     always move as one */
  body[data-view="3d"] { --cam: var(--pose-entr, none); }
  body[data-view="3d"][data-screen="dialog"] { --cam: var(--pose-sofa, none); }
  body[data-view="3d"][data-screen="memories"] { --cam: var(--pose-fotos, none); }
  body[data-view="3d"][data-screen="people"] { --cam: var(--pose-menschen, none); }
  body[data-view="3d"][data-screen="graph"] { --cam: var(--pose-graph, none); }
  body[data-view="3d"][data-screen="off"] { --cam: var(--pose-door, none); }
  body[data-view="3d"] .r3-stage {
    position: absolute;
    left: 0;
    top: 0;
    width: calc(var(--r3-u, 1.2px) * 1600);
    height: calc(var(--r3-u, 1.2px) * 640);
    transform-origin: 0 0;   /* pose math rotates about the x=0 axis */
    transform-style: preserve-3d;
    transform: var(--cam, none);
    transition: transform 0.8s var(--ease-soft);
    will-change: transform;
    pointer-events: none;
  }

  body[data-view="3d"] .r3-plane { position: absolute; }  /* no backface culling: the window
     wall's painted face points out of the room and shows us its back */
  /* at the board poses the camera stands between the furniture and the
     wall — the edge-on billboards would smear across the view */
  body[data-view="3d"] .r3-bill { transition: opacity 0.4s ease; }
  body[data-view="3d"][data-screen="memories"] .r3-bill, body[data-view="3d"][data-screen="people"] .r3-bill, body[data-view="3d"][data-screen="graph"] .r3-bill { opacity: 0; }
  /* walls are painted in vertical strips (each its own paint budget) */
  body[data-view="3d"] .r3-plane .r3-strip { position: absolute; top: 0; height: 100%; display: block; }
  /* state-driven art (table set, beam, canvas) lives in small light-DOM
     overlays — CSS rules don't reach <use> shadow clones */
  body[data-view="3d"] .r3-plane .rm-dyn { position: absolute; top: 0; height: 100%; display: block; }
  body[data-view="3d"] .r3-back {
    left: 0; top: 0;
    width: calc(var(--r3-u) * 1600);
    height: calc(var(--r3-u) * 640);
  }
  body[data-view="3d"] .r3-right {
    left: calc(var(--r3-u) * 1600); top: 0;
    width: calc(var(--r3-u) * 1200);
    height: calc(var(--r3-u) * 640);
    transform-origin: left center;
    transform: rotateY(-90deg);
  }
  body[data-view="3d"] .r3-left {
    left: 0; top: 0;
    width: calc(var(--r3-u) * 1200);
    height: calc(var(--r3-u) * 640);
    transform-origin: left center;
    transform: rotateY(-90deg);
  }
  body[data-view="3d"] .r3-floor {
    left: 0; top: calc(var(--r3-u) * 640);
    width: calc(var(--r3-u) * 1600);
    height: calc(var(--r3-u) * 1200);
    transform-origin: center top;
    transform: rotateX(90deg);
  }
  body[data-view="3d"] .r3-ceiling {
    left: 0; top: calc(var(--r3-u) * -1200);
    width: calc(var(--r3-u) * 1600);
    height: calc(var(--r3-u) * 1200);
    transform-origin: center bottom;
    transform: rotateX(-90deg);
  }


  /* The ENTRY WALL: the fourth wall at z = room depth, with a doorway hole.
     Standing outside (off) the camera faces it; the open doorway shows the
     REAL room behind, and entering is one continuous dolly through it.
     It rides its OWN stage (same camera pose, pushed to the room's near
     depth) and is painted as plain strips INTO that stage's layer — a
     3D-transformed plane that starts left of the viewport drops exactly
     its offscreen width from its right end (raster anchored at the element
     origin), so the wall must not be a transformed plane itself. */
  body[data-view="3d"] .r3-ewall-strip { position: absolute; top: 0; height: calc(var(--r3-u) * 640); }
  /* once inside, the wall RESTS behind the camera (at the through-pose,
     invisible) — so switching off replays the pass in reverse: the door
     frame sweeps back into view as the camera retreats through it */
  body[data-view="3d"]:not([data-screen="off"]) .r3-estage {
    transform: var(--pose-thru, none);
    opacity: 0;
    visibility: hidden;
    transition: transform 2s var(--ease-soft), opacity 0.9s ease 0.6s,
      visibility 0s linear 1.5s;
  }
  /* the doorway itself is a small plane (always starts onscreen, so the
     raster bug can't touch it) whose leaf swings in real 3D */
  body[data-view="3d"] .entry-doorway {
    position: absolute;
    left: calc(var(--r3-u) * 680);
    top: calc(var(--r3-u) * 172);
    width: calc(var(--r3-u) * 240);
    height: calc(var(--r3-u) * 468);
    transform: translateZ(0);
    transform-style: preserve-3d;
  }
  body[data-view="3d"] .entry-door {
    position: absolute;
    inset: 0;
    /* the leaf is rendered in Blender (blender/room.blend, cam_door) */
    background: url("/static/room/door.webp") center / 100% 100% no-repeat,
      linear-gradient(160deg, #96754a, #6f5330);
    transform-origin: left center;
    transition: transform 1s var(--ease-soft);
  }
  body[data-view="3d"] .entry-door .door-handle { display: none; }
  body[data-view="3d"] #room[data-door="open"] .entry-door { transform: rotateY(-104deg); }
  /* the peephole rides the leaf at eye height (design: screen-tuerspion);
     em-scaled — this font-size is its only size knob per context */
  body[data-view="3d"] #spion {
    display: block;
    position: absolute;
    left: 50%;
    top: calc(var(--r3-u) * 96);
    transform: translateX(-50%);
    font-size: calc(var(--r3-u) * 6.4);
  }
  body[data-view="3d"] .entry-bell {
    position: absolute;
    left: calc(var(--r3-u) * 968);
    /* bell plates sit at handle height, not at eye level (handle: y 406) */
    top: calc(var(--r3-u) * 352);
    pointer-events: auto;
  }

  /* standing at the door: hint + progress live at the bottom of the screen,
     in front of the wall; the 2D door drawing is the phone fallback */
  body[data-view="3d"][data-screen="off"] section[data-screen="off"] {
    justify-content: flex-end;
    align-items: flex-start;
    padding-left: 8vw;
    padding-bottom: 7vh;
    max-width: none;
    pointer-events: none;
  }
  body[data-view="3d"][data-screen="off"] section[data-screen="off"] .off-hint, body[data-view="3d"][data-screen="off"] section[data-screen="off"] .door-boot, body[data-view="3d"][data-screen="off"] section[data-screen="off"] .error { pointer-events: auto; }
  body[data-view="3d"] section[data-screen="off"] .door-scene { display: none; }

  /* the walk through the door is a slow, deliberate camera move */
  body[data-view="3d"][data-screen="off"] .r3-stage:not(.r3-estage), body[data-view="3d"][data-entering] .r3-stage:not(.r3-estage) { transition-duration: 2s; }
  /* the entry stage: same camera, pushed to the room's near depth; its
     transitions are written out in full so the duration rule above never
     stretches the opacity fade */
  body[data-view="3d"] .r3-estage {
    transform: var(--cam, none) translateZ(calc(var(--r3-u, 1.2px) * 1200));
    transition: transform 0.8s var(--ease-soft), opacity 0.5s ease, visibility 0s;
  }
  /* walking out: the wall starts BEHIND the camera (through-pose) and
     sweeps back into view as the camera retreats through the doorway —
     the quick early fade finishes while it is still outside the viewport,
     so the whole sweep-in plays fully opaque, then the door swings shut */
  body[data-view="3d"][data-screen="off"] .r3-estage {
    transition: transform 2s var(--ease-soft), opacity 0.3s ease 0.25s, visibility 0s;
  }
  /* walking IN: the entry wall alone flies past the camera — the doorway
     hole stays pinned to the eye and sweeps beyond the viewport edges
     (~1.1s in), a real pass through the door; the short late fade only
     covers the moment the wall crosses the camera plane (~1.4s) */
  body[data-view="3d"][data-entering]:not([data-screen="off"]) .r3-estage {
    transform: var(--pose-thru, none);
    opacity: 0;
    visibility: hidden;
    transition: transform 2s var(--ease-soft), opacity 0.3s ease 1.15s,
      visibility 0s linear 1.5s;
  }

  body[data-view="3d"] #room .rm-hand {
    font-family: var(--font-hand);
    font-weight: 500;
    font-size: 44px;
    fill: var(--ink-1);
  }

  /* The REAL boards on the right wall (percent of that plane). Interactive —
     a tap on a mini polaroid hero-zooms it open. */
  body[data-view="3d"] .room-board {
    position: absolute;
    pointer-events: auto;
    overflow-y: auto;
    scrollbar-width: none;
  }
  /* the garlands hang INSIDE the boards now — the grids duck below them */
  body[data-view="3d"] #room-board-fotos { padding-top: calc(var(--r3-u) * 74); }
  body[data-view="3d"] #room-board-menschen { padding-top: calc(var(--r3-u) * 74); }
  body[data-view="3d"] .board-garland { position: absolute; pointer-events: none; }
  body[data-view="3d"] .board-garland text {
    /* letterpress capitals on the paper discs (ref: baker's-twine banner) */
    font-family: var(--font-serif);
    font-weight: 700;
    fill: #362c1e;
  }
  /* the garland IS the label now — the big overlay heading only repeats it */
  body[data-view="3d"][data-screen="memories"] .greeting, body[data-view="3d"][data-screen="people"] .greeting { display: none; }
  body[data-view="3d"] .room-board::-webkit-scrollbar { display: none; }
  body[data-view="3d"] #room-board-fotos { left: 8.333%; top: 25%; width: 35%;     height: 46.875%; }
  body[data-view="3d"] #room-board-menschen { left: 53%;     top: 25%; width: 18.167%; height: 46.875%; }
  body[data-view="3d"] #room-whiteboard { position: absolute; left: 75.33%; top: 28.75%;
                         width: 18.08%; height: 37.03%; }
  body[data-view="3d"] #room-whiteboard #wb-sheet {
    width: 100%; height: 100%;
    background: none; border-radius: 0; box-shadow: none;
  }
  body[data-view="3d"] #room-whiteboard #wb-sheet svg { width: 100%; height: 100%; }

  /* photo-sized polaroids — like real prints on a big cork board */
  body[data-view="3d"] .room-board .pinboard {
    grid-template-columns: repeat(auto-fill, minmax(78px, 1fr));
    gap: 0.9rem 0.6rem;
    padding: 0.7rem 0.6rem;
  }
  body[data-view="3d"] #room-board-menschen .pinboard { grid-template-columns: repeat(auto-fill, minmax(70px, 1fr)); }
  body[data-view="3d"] .room-board .polaroid { padding: 4px 4px 0.45rem; box-shadow: 0 4px 10px rgba(0, 0, 0, 0.35); }
  body[data-view="3d"] .room-board .polaroid::before { width: 10px; height: 10px; top: -5px; }
  body[data-view="3d"] .room-board .polaroid figcaption {
    font-size: 0.8rem;
    padding-top: 0.2rem;
    -webkit-line-clamp: 1;
  }
  body[data-view="3d"] .room-board .polaroid .frame-date { display: none; }
  body[data-view="3d"] .room-board .sticky-note {
    font-size: 0.95rem;
    padding: 0.5rem 0.7rem;
    max-width: none;
  }

  /* the projection surface on the pulled-down canvas (back wall plane) */
  body[data-view="3d"] #room-canvas {
    position: absolute;
    /* centred on the canvas SHEET (art 1080..1448 x 34..444) */
    left: 67.8%;
    top: 6.6%;
    width: 22.4%;
    height: 60.5%;
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
  }
  body[data-view="3d"] #room-canvas img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    /* projected light, not a print: slightly warm and translucent */
    filter: sepia(0.12) brightness(1.03);
    opacity: 0.95;
    border-radius: 2px;
  }
  body[data-view="3d"] #room-canvas img:not([src]) { display: none; }

  /* the paper/cork body backgrounds sit behind the room; screens above it */
  body[data-view="3d"] .screen { animation: screen-in 0.45s var(--ease-soft); }

  /* the reception panel docks left; the room stays the star (scoped to the
     menu section — during the door walkthrough other sections overlay) */
  body[data-view="3d"][data-screen="main_menu"] section[data-screen="main_menu"] {
    max-width: none;
    align-items: flex-start;
    justify-content: center;
    padding-left: 4vw;
  }
  body[data-view="3d"][data-screen="main_menu"] .greeting { display: none; }

  /* the quiet menu actions sit in the room — paper chips keep them readable */
  body[data-view="3d"] .btn-quiet {
    background: var(--paper-0);
    border-radius: 999px;
    padding: 0.5rem 1.1rem;
    box-shadow: var(--shadow-card);
    text-decoration: none;
  }

  /* Telling & listening: ONE paper panel docked left over the calm lamp
     corner (the reception-menu language) — sofa centre and the canvas on
     the right stay completely clear */
  body[data-view="3d"][data-screen="dialog"] .screen {
    left: 6vw;
    right: auto;
    top: 9vh;
    bottom: auto;
    width: min(430px, 40vw);
    max-width: none;
    max-height: calc(100vh - var(--dock-h) - 12vh);
    justify-content: flex-start;
    align-items: flex-start;
    gap: 0.9rem;
    padding: 1.5rem 1.6rem 1rem;
    background: var(--paper-0);
    border-radius: 22px;
    box-shadow: 0 14px 40px rgba(60, 40, 15, 0.28);
    overflow: hidden;
  }
  /* the PTT button carries the state (it pulses with the mic level) —
     the big idle halo is retired on the desktop */
  body[data-view="3d"][data-screen="dialog"] .ring-wrap { display: none; }
  body[data-view="3d"] section[data-screen="dialog"] .dialog-top { width: 100%; }
  body[data-view="3d"] section[data-screen="dialog"] .state-text {
    text-align: left;
    font-size: 1.15rem;
    min-height: 1.5em;
    margin: 0;
  }
  body[data-view="3d"] section[data-screen="dialog"] .chat-scroll {
    min-height: 4rem;
  }
  /* cancel becomes the panel's quiet foot row */
  /* the two enders sit in the panel header, right of the badge */
  body[data-view="3d"] section[data-screen="dialog"] .dialog-actions { gap: 0.4rem; }
  body[data-view="3d"] section[data-screen="dialog"] .btn-done {
    padding: 0.4rem 0.85rem;
    font-size: 0.95rem;
  }

  /* The fixed sections float OVER the room. Where the real boards must be
     clickable, the empty section area lets clicks through. */
  body[data-view="3d"][data-screen="main_menu"] section[data-screen="main_menu"], body[data-view="3d"][data-screen="memories"] section[data-screen="memories"], body[data-view="3d"][data-screen="people"] section[data-screen="people"], body[data-view="3d"][data-screen="graph"] section[data-screen="graph"] { pointer-events: none; }
  body[data-view="3d"][data-screen="main_menu"] section[data-screen="main_menu"] button, body[data-view="3d"][data-screen="memories"] section[data-screen="memories"] button, body[data-view="3d"][data-screen="people"] section[data-screen="people"] button, body[data-view="3d"][data-screen="graph"] section[data-screen="graph"] button { pointer-events: auto; }

  /* at the wall the scenery labels + real boards carry the scene — the
     section keeps only its back button, pinned bottom centre */
  body[data-view="3d"][data-screen="memories"] .greeting, body[data-view="3d"][data-screen="people"] .greeting, body[data-view="3d"][data-screen="graph"] .greeting { display: none; }
  body[data-view="3d"][data-screen="memories"] #memories-back, body[data-view="3d"][data-screen="people"] #people-back, body[data-view="3d"][data-screen="graph"] #graph-back {
    position: fixed;
    left: calc(50% - 11.5rem);
    bottom: calc(2.2rem + env(safe-area-inset-bottom));
    transform: translateX(-50%);
    width: auto;
  }
  /* the talk button follows onto the board views (menu commands by
     voice: Zurueck, Menschen ansehen, Ausschalten ...) */
  body[data-view="3d"][data-screen="memories"] .controls, body[data-view="3d"][data-screen="people"] .controls, body[data-view="3d"][data-screen="graph"] .controls { display: flex; }
  body[data-view="3d"][data-screen="memories"] .btn-side, body[data-view="3d"][data-screen="people"] .btn-side, body[data-view="3d"][data-screen="graph"] .btn-side { visibility: hidden; }

}

@keyframes screen-in {
  from { opacity: 0; transform: translateY(14px); }
}

@media (prefers-reduced-motion: reduce) {
  .r3-stage { transition: none !important; }
  .screen,
  #memory-viewer:not([hidden]),
  #camera-overlay:not([hidden]),
  #ob-face-overlay:not([hidden]) { animation: none !important; }
}

/* ==========================================================================
   Ansicht-Umschalter: the gear top right (direct child of body). Opens a
   small paper card with the 3D/2D choice; the preference lives in
   localStorage ("memobox.view"), body[data-view] is the effective view.
   ========================================================================== */

#view-gear-wrap {
  position: fixed;
  top: calc(0.7rem + env(safe-area-inset-top));
  right: 0.9rem;
  z-index: 16;   /* above screens & dialog-cancel, below camera/toast/viewer */
  font-family: var(--font-sans);
}
#view-gear {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border: none;
  border-radius: 999px;
  background: var(--paper-0);
  color: var(--ink-1);
  box-shadow: 0 3px 10px rgba(60, 40, 20, 0.25);
  cursor: pointer;
}
#view-gear svg {
  width: 1.5rem;
  height: 1.5rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
}
#view-menu {
  position: absolute;
  right: 0;
  top: calc(100% + 0.5rem);
  min-width: 15rem;
  padding: 0.7rem;
  background: var(--paper-0);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lift);
}
.view-menu-title {
  margin: 0.1rem 0.4rem 0.4rem;
  font-size: 0.82rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.view-opt {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.1rem;
  width: 100%;
  min-height: 52px;
  padding: 0.55rem 0.8rem;
  margin-top: 0.3rem;
  border: 2px solid transparent;
  border-radius: 12px;
  background: var(--paper-1);
  font: inherit;
  color: var(--ink-1);
  text-align: left;
  cursor: pointer;
}
.view-opt[aria-pressed="true"] {
  border-color: var(--terracotta);
  background: var(--cream);
}
.view-opt-name { font-weight: 700; font-size: 1.05rem; }
.view-opt-sub { font-size: 0.85rem; color: var(--ink-2); }
/* out of the way during dialogs (the cancel chip owns that corner on 2d)
   and during the door cinematics */
body[data-screen="dialog"] #view-gear-wrap,
body[data-doorboot] #view-gear-wrap,
body[data-entering] #view-gear-wrap,
body[data-doorplay] #view-gear-wrap { display: none; }
body[data-doorboot] #account-chip,
body[data-entering] #account-chip,
body[data-doorplay] #account-chip,
/* the dialog owns the stage — and its cancel chip owns the corner the
   account chip would otherwise overlap */
body[data-screen="dialog"] #account-chip { display: none; }

/* cascade repair: scoping the desktop block raised .btn-quiet to
   (0,2,1), which out-specified the tiny-chip padding at .menu-tiny
   .btn-quiet — restore the v70 winner */
body[data-view="3d"] .menu-tiny .btn-quiet { padding: 0.25rem 0.8rem; }

/* ==========================================================================
   Gunter 2D (design/gunter/*.png, verbatim): the hub "Erinnerungsstation"
   replaces greeting + menu panel on main_menu, plus the two entry chooser
   screens and the quiz preview. Colour-coded tracks — green (alte
   Erinnerung), amber (neue Erinnerung), purple (Quiz); rounded sans
   (Nunito, like the mockups), circle icon badges, circle chevrons.
   ========================================================================== */

/* track palettes (sampled from the mockups) */
.g-green {
  --g-accent: #69a56c; --g-deep: #46824f; --g-ink: #3e6b45;
  --g-tile-bg: #ecf0e8; --g-band: #dde4cf; --g-card-bg: #fafbf5;
}
.g-amber {
  --g-accent: #f3b821; --g-deep: #d99f0e; --g-ink: #7d5f0e;
  --g-tile-bg: #fbf2e5; --g-band: #f6e6bf; --g-card-bg: #fffdf4;
}
.g-purple {
  --g-accent: #8e76c4; --g-deep: #604c9e; --g-ink: #4f3e85;
  --g-tile-bg: #e9e2f5; --g-band: #e3d9f0; --g-card-bg: #fcfaff;
}

/* the hub only exists in the flat view */
body[data-view="3d"] .g-home { display: none; }
body[data-view="2d"] section[data-screen="main_menu"] .greeting,
body[data-view="2d"] section[data-screen="main_menu"] .menu-panel { display: none; }

/* screen backgrounds (these screens are not in the linen list; the hub
   rule outranks the linen rule by specificity) */
body[data-view="2d"][data-screen="main_menu"] { background: linear-gradient(180deg, #e9e9d7, #e8e8e1); }
body[data-view="2d"][data-screen="choose_old"] { background: linear-gradient(180deg, #ecefe5, #f1f2eb); }
body[data-view="2d"][data-screen="choose_new"] { background: linear-gradient(180deg, #faf3e2, #fbf7ec); }
body[data-view="2d"][data-screen="quiz"] { background: linear-gradient(180deg, #f2eaf6, #f3edf8); }

/* --- the hub --- */
.g-home {
  --g-accent: #69a56c; /* the green heart under the title */
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  max-width: 560px;
  font-family: var(--font-sans);
}
.g-title {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 1.7rem;
  font-weight: 700;
  line-height: 1.25;
  color: var(--g-ink, var(--ink-0));
  text-align: center;
}
.g-home .g-title { font-size: 2rem; color: #2e2b24; }
.g-sub {
  margin: 0.4rem 0 0;
  font-size: 1.05rem;
  color: rgba(70, 75, 60, 0.75);
  text-align: center;
}
.g-divider {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  margin: 0.9rem 0 1.2rem;
  color: var(--g-accent, #69a56c);
}
.g-divider span { width: 2.2rem; border-top: 2px dashed currentColor; opacity: 0.7; }
.g-divider svg { width: 1.15rem; height: 1.15rem; fill: currentColor; }
.g-tiles {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
  width: 100%;
}
.g-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.9rem;
  padding: 1.4rem 1rem 1.2rem;
  border: none;
  border-radius: 22px;
  background: var(--g-tile-bg);
  box-shadow: 0 4px 14px rgba(80, 70, 40, 0.10);
  font: inherit;
  cursor: pointer;
}
.g-tile-wide { grid-column: 1 / -1; }
.g-tile-label {
  font-size: 1.25rem;
  font-weight: 700;
  line-height: 1.3;
  color: var(--g-ink);
  text-align: center;
}
.g-badge {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 68px;
  height: 68px;
  border-radius: 50%;
  background: var(--g-accent);
  color: #fff;
  box-shadow: 0 0 0 7px rgba(255, 255, 255, 0.75);
}
.g-badge svg { width: 55%; height: 55%; fill: none; stroke: currentColor; stroke-width: 1.7; }
.g-chevron {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  background: var(--g-deep);
  color: #fff;
}
.g-chevron svg { width: 55%; height: 55%; fill: none; stroke: currentColor; stroke-width: 2.4; }
.g-home-quiet {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem;
  margin-top: 1.2rem;
}
/* the parked menu buttons (placeBoards) as small quiet pills */
body[data-view="2d"] .g-home-quiet > * {
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  gap: 0.4rem;
  width: auto;
  min-height: 48px;
  margin: 0;
  padding: 0.5rem 1rem;
  border: none;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.85);
  box-shadow: 0 2px 8px rgba(80, 70, 40, 0.12);
  font-size: 0.98rem;
  font-weight: 700;
  color: var(--ink-1);
  white-space: nowrap;
  text-decoration: none;
}
body[data-view="2d"] .g-home-quiet .menu-ico { display: none; }
.g-foot {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  width: 100%;
  margin-top: auto;
  padding: 0.9rem 1.2rem calc(0.9rem + env(safe-area-inset-bottom));
  background: var(--g-band);
  color: var(--g-ink);
  font-size: 0.92rem;
  line-height: 1.35;
}
.g-foot svg { width: 1.5rem; height: 1.5rem; flex: none; fill: none; stroke: currentColor; stroke-width: 1.6; }
.g-home .g-foot {
  margin-top: 1.4rem;
  padding: 0;
  background: none;
  color: #6d7263;
  font-size: 0.85rem;
}

/* --- the chooser / quiz screens (full-bleed bands, centered body) --- */
body[data-view="2d"] .g-screen {
  padding: 0;
  gap: 0;
  max-width: none;
  margin: 0;
  justify-content: flex-start;
  font-family: var(--font-sans);
}
.g-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.8rem;
  width: 100%;
  /* the right edge stays clear of the fixed gear button */
  padding: calc(0.6rem + env(safe-area-inset-top)) calc(1.9rem + 52px)
           0.8rem 1rem;
  background: var(--g-band);
}
.g-top-badge {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 58px;
  height: 58px;
  border-radius: 50%;
  background: var(--g-accent);
  color: #fff;
  box-shadow: 0 0 0 5px rgba(255, 255, 255, 0.85);
}
.g-top-badge svg { width: 55%; height: 55%; fill: none; stroke: currentColor; stroke-width: 1.7; }
.g-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  min-height: 48px;
  padding: 0.5rem 1.05rem;
  border: none;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.92);
  box-shadow: 0 2px 8px rgba(80, 70, 40, 0.12);
  font: inherit;
  font-weight: 700;
  font-size: 1rem;
  color: var(--g-ink);
  cursor: pointer;
  white-space: nowrap;
}
.g-pill svg { width: 1.15rem; height: 1.15rem; fill: none; stroke: currentColor; stroke-width: 2; }
.g-pill-solid { background: var(--g-deep); color: #fff; }
.g-body {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  width: 100%;
  max-width: 560px;
  margin: 0 auto;
  padding: 1.4rem 1.2rem 1.6rem;
}
.g-body .g-title, .g-body .g-sub { align-self: center; max-width: 26rem; }
.g-card {
  display: flex;
  align-items: center;
  gap: 1rem;
  width: 100%;
  margin-top: 1.1rem;
  padding: 1.1rem 1rem;
  border: none;
  border-radius: 20px;
  background: var(--g-card-bg);
  box-shadow: 0 4px 16px rgba(80, 70, 40, 0.10);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.g-card .g-badge { width: 76px; height: 76px; box-shadow: none; }
.g-card .g-chevron { margin-left: auto; }
.g-card-text { display: flex; flex-direction: column; gap: 0.25rem; min-width: 0; }
.g-card-title { font-size: 1.35rem; font-weight: 700; line-height: 1.25; color: var(--g-ink); }
.g-card-sub { font-size: 0.98rem; line-height: 1.35; color: #75756a; }

/* --- QUIZ DEMO (removable: delete with the fenced blocks) --- */
.g-quiz-card {
  flex-direction: column;
  text-align: center;
  gap: 0.7rem;
  cursor: default;
  padding: 1.3rem 1.2rem 1rem;
}
.g-quiz-q {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: #bca5db;
  color: #fff;
  font-size: 1.9rem;
  font-weight: 700;
}
.g-quiz-question {
  margin: 0.2rem 0 0;
  font-size: 1.35rem;
  font-weight: 700;
  line-height: 1.35;
  color: var(--g-ink);
}
.g-quiz-read {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  min-height: 44px;
  border: none;
  background: none;
  font: inherit;
  font-weight: 700;
  color: var(--g-deep);
  cursor: pointer;
}
.g-quiz-read svg { width: 1.3rem; height: 1.3rem; fill: none; stroke: currentColor; stroke-width: 1.8; }
.g-answer {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  width: 100%;
  margin-top: 0.8rem;
  padding: 0.7rem 0.9rem;
  border: none;
  border-radius: 999px;
  background: var(--g-card-bg);
  box-shadow: 0 3px 12px rgba(80, 70, 40, 0.10);
  font: inherit;
  cursor: pointer;
}
.g-answer-letter {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: #b599da;
  color: #fff;
  font-weight: 700;
  font-size: 1.15rem;
}
.g-answer-text { font-size: 1.15rem; font-weight: 700; color: var(--g-ink); text-align: left; }
.g-answer .g-chevron { margin-left: auto; width: 40px; height: 40px; background: #a386cf; }
#quiz-ack:not([hidden]) {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.1rem;
  margin-top: 1.3rem;
}
.g-quiz-ack {
  margin: 0;
  font-size: 1.3rem;
  font-weight: 700;
  line-height: 1.4;
  color: var(--g-ink);
  text-align: center;
}
/* --- /QUIZ DEMO --- */

/* narrow phones: the two hub tiles stack */
@media (max-width: 480px) {
  .g-tiles { grid-template-columns: 1fr; }
}

/* --- gate screens in the flat view: Gunter's language ------------------
   The 3D night keeps the paper cards above; in 2D the same markup wears
   the mockup skin — Nunito, the green track, white cards, pill buttons,
   circle badges (design/gunter, same tokens as the hub). */
body[data-view="2d"][data-screen="login"],
body[data-view="2d"][data-screen="person"] {
  background: linear-gradient(180deg, #e9e9d7, #e8e8e1);
}
/* the register form outgrows small screens: let the gate scroll */
section[data-screen="person"] { overflow-y: auto; }
section[data-screen="person"] .login-card { margin: auto 0; flex: none; }
/* focus ring in the track colour, not the room's terracotta */
body[data-view="2d"] .login-card input:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(105, 165, 108, 0.45);
}
body[data-view="2d"] .login-card {
  --g-accent: #69a56c; --g-deep: #46824f; --g-ink: #3e6b45;
  --g-band: #dde4cf; --g-card-bg: #fafbf5;
  background: var(--g-card-bg);
  border: 2px solid var(--g-band);
  border-radius: 22px;
  box-shadow: 0 10px 24px rgba(70, 80, 60, 0.14);
  font-family: var(--font-sans);
}
body[data-view="2d"] .login-card .wordmark {
  font-family: var(--font-sans);
  font-weight: 700;
  color: #2e2b24;
}
.login-card .g-divider { display: none; }
body[data-view="2d"] .login-card .g-divider { display: flex; margin: -0.4rem 0 0.2rem; }
body[data-view="2d"] .person-lead {
  font-family: var(--font-sans);
  font-weight: 700;
  color: var(--g-ink);
}
body[data-view="2d"] .login-card label {
  font-family: var(--font-sans);
  letter-spacing: 0.05em;
  color: var(--g-ink);
}
body[data-view="2d"] .login-card input {
  border: 2px solid var(--g-band);
  border-bottom-width: 2px;
  border-radius: 14px;
  background: #fff;
}
body[data-view="2d"] .login-card .btn {
  border: 2px solid var(--g-band);
  border-bottom-width: 2px;
  border-radius: 999px;
  background: #fff;
  font-weight: 700;
  color: var(--g-ink);
}
body[data-view="2d"] .login-card .btn-primary {
  background: var(--g-deep);
  border-color: var(--g-deep);
  color: #fff;
}
body[data-view="2d"] .person-list .btn {
  padding: 0.5rem 1.2rem 0.5rem 0.55rem;
}
body[data-view="2d"] .person-portrait { border: 2px solid var(--g-band); }
body[data-view="2d"] .person-role { color: var(--g-ink); opacity: 0.8; }
body[data-view="2d"] .face-preview {
  border: 3px solid var(--g-accent);
  box-shadow: 0 10px 24px rgba(70, 80, 60, 0.14);
}
body[data-view="2d"] .person-hint { color: var(--g-ink); opacity: 0.75; }
body[data-view="2d"] #account-chip {
  background: #fff;
  border: 2px solid #dde4cf;
  font-family: var(--font-sans);
  font-weight: 700;
  color: #3e6b45;
}
body[data-view="2d"] #account-chip .btn { border-radius: 999px; }
body[data-view="2d"] .admin-corner { border-radius: 999px; font-family: var(--font-sans); }

/* --- 2D flow colours: the screen says which track you are on ---------
   Green carries "alte Erinnerung auffrischen" from the chooser into the
   running conversation; amber carries "neue Erinnerung einspeisen" into
   the telling. Same gradients as the choosers, so the hand-over is
   seamless (design/gunter tracks). */
body[data-view="2d"][data-flow="conversation"] {
  --g-accent: #69a56c; --g-deep: #46824f; --g-ink: #3e6b45; --g-band: #dde4cf;
  background: linear-gradient(180deg, #ecefe5, #f1f2eb);
}
body[data-view="2d"][data-flow="new_memory"] {
  --g-accent: #f3b821; --g-deep: #d99f0e; --g-ink: #7d5f0e; --g-band: #f6e6bf;
  background: linear-gradient(180deg, #faf3e2, #fbf7ec);
}
body[data-view="2d"][data-flow] .controls .btn-side {
  background: #fff;
  border: 2px solid var(--g-band);
  border-bottom-width: 2px;
  color: var(--g-ink);
  font-weight: 700;
}
body[data-view="2d"][data-flow] section[data-screen="dialog"] .dialog-cancel {
  color: var(--g-ink);
}
body[data-view="2d"][data-flow] section[data-screen="dialog"] .btn-done {
  background: var(--g-deep);
  color: #fff;
}
body[data-view="2d"][data-flow] .dialog-badges .badge {
  background: #fff;
  border: 2px solid var(--g-band);
  color: var(--g-ink);
}

/* the object camera follows the track in 2D: light tinted stage instead of
   the 3D night, buttons in the flow colours */
body[data-view="2d"][data-flow="conversation"] #camera-overlay {
  background: linear-gradient(180deg, rgba(236, 239, 229, 0.97), rgba(241, 242, 235, 0.97));
}
body[data-view="2d"][data-flow="new_memory"] #camera-overlay {
  background: linear-gradient(180deg, rgba(250, 243, 226, 0.97), rgba(251, 247, 236, 0.97));
}
body[data-view="2d"][data-flow] #camera-overlay .btn {
  background: #fff;
  border: 2px solid var(--g-band);
  border-bottom-width: 2px;
  border-radius: 999px;
  color: var(--g-ink);
  font-weight: 700;
}
body[data-view="2d"][data-flow] #camera-overlay .btn-primary {
  background: var(--g-deep);
  border-color: var(--g-deep);
  color: #fff;
}
body[data-view="2d"][data-flow] #camera-overlay .camera-polaroid,
body[data-view="2d"][data-flow] #camera-overlay #camera-video {
  box-shadow: 0 14px 34px rgba(70, 80, 60, 0.25);
}

/* --- the view choice inside the gate cards -------------------------------
   The corner gear stays, but the login says it out loud: pick 2D or 3D
   before the camera has recognised you. Same preference, same handlers. */
.view-choice {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  margin-top: 0.4rem;
  padding-top: 0.9rem;
  border-top: 1px solid rgba(60, 40, 20, 0.12);
}
.view-choice-label {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-2);
  margin-right: 0.3rem;
}
.view-pill {
  font: inherit;
  font-size: 0.88rem;
  font-weight: 600;
  padding: 0.45rem 0.9rem;
  border-radius: 999px;
  border: 1.5px solid var(--paper-4);
  background: var(--paper-0);
  color: var(--ink-1);
  cursor: pointer;
}
.view-pill[aria-pressed="true"] {
  border-color: var(--terracotta);
  background: var(--cream);
  color: var(--ink-0);
}
body[data-view="2d"] .view-choice { border-top-color: var(--g-band, #dde4cf); }
body[data-view="2d"] .view-pill {
  font-family: var(--font-sans);
  font-weight: 700;
  background: #fff;
  border: 2px solid var(--g-band, #dde4cf);
  color: var(--g-ink, #3e6b45);
}
body[data-view="2d"] .view-pill[aria-pressed="true"] {
  background: var(--g-deep, #46824f);
  border-color: var(--g-deep, #46824f);
  color: #fff;
}

/* --- the off screen in the flat view: Gunter's language ------------------
   The 3D night keeps its brass doorbell; in 2D the same markup becomes a
   quiet start card in the hub's palette — white card, green heart, one big
   green start button. Wording drops the bell metaphor (per-view spans). */
.only-2d { display: none; }
body[data-view="2d"] .only-2d { display: inline; }
body[data-view="2d"] .only-2d.g-divider { display: flex; }
body[data-view="2d"] .only-3d { display: none; }

body[data-view="2d"][data-screen="off"] {
  background: linear-gradient(180deg, #e9e9d7, #e8e8e1);
}
body[data-view="2d"] .door-bell {
  background: #fafbf5;
  border: 2px solid #dde4cf;
  border-radius: 22px;
  box-shadow: 0 10px 24px rgba(70, 80, 60, 0.14);
  padding: 2.1rem 2.8rem 1.9rem;
  gap: 0.9rem;
  font-family: var(--font-sans);
}
body[data-view="2d"] .door-name {
  order: -1;                     /* the name greets first, like the hub title */
  font-family: var(--font-sans);
  font-weight: 800;
  font-size: 1.7rem;
  color: #2e2b24;
  background: none;
  border: none;
  box-shadow: none;
  width: auto;
  max-width: 70vw;
}
body[data-view="2d"] .door-bell .g-divider {
  order: -1;                     /* between name and button, like the hub */
  margin: -0.2rem 0 0.3rem;
  color: #69a56c;
}
body[data-view="2d"] #power-button {
  width: 112px;
  height: 112px;
  background: #46824f;           /* the track's deep green, like the badges */
  color: #fff;
  box-shadow: 0 10px 22px rgba(70, 80, 60, 0.28);
}
body[data-view="2d"] #power-button svg { stroke: #fff; }
body[data-view="2d"] section[data-screen="off"] .off-hint {
  font-family: var(--font-sans);
  font-style: normal;
  font-weight: 600;
  color: #3e6b45;
}
body[data-view="2d"] .door-boot .state-text {
  font-family: var(--font-sans);
  color: rgba(70, 75, 60, 0.8);
}
body[data-view="2d"] .door-boot .boot-track { background: #dde4cf; }
body[data-view="2d"] #door-boot-bar { background: #69a56c; }
body[data-view="2d"] section[data-screen="off"] .error { color: #7d5f0e; }
/* the peephole belongs to the door story — the flat card starts without it */
body[data-view="2d"] #spion { display: none; }

/* chat thread in the 2D tracks: white box bubbles with the band, the
   person's bubble filled in the flow's deep colour */
body[data-view="2d"] .bubble-user {
  background: var(--g-deep, #46824f);
  color: #fff;
}
body[data-view="2d"] .bubble-box {
  background: #fff;
  border: 1.5px solid var(--g-band, #dde4cf);
  color: var(--ink-0);
}
body[data-view="2d"] .bubble-thinking span { background: var(--g-ink, #3e6b45); }
body[data-view="2d"] #chat-input-row {
  background: #fff;
  border: 2px solid var(--g-band, #dde4cf);
}
body[data-view="2d"] #chat-input-row:focus-within {
  box-shadow: 0 6px 18px rgba(70, 80, 60, 0.14), 0 0 0 3px rgba(105, 165, 108, 0.35);
}
body[data-view="2d"] .chat-tool { color: var(--g-ink, #3e6b45); }
body[data-view="2d"] #chat-send { background: var(--g-deep, #46824f); }
body[data-view="2d"] #chat-input-row {
  left: 1rem;
  right: calc(1.1rem + 84px + 1rem + env(safe-area-inset-right));
}

/* a person without a password: pick them and the box says what works
   instead — the entry is dimmed, never a silent dead end */
.person-list .btn.person-locked { opacity: 0.55; }

/* the inline password row on a person's card (self or Verwaltung) */
.pw-row { display: flex; gap: 0.6rem; align-items: center; }
.pw-row input {
  flex: 1;
  min-width: 0;
  font: inherit;
  font-size: var(--fs-base);
  padding: 0.6rem 0.9rem;
  border: 1.5px solid var(--paper-4);
  border-bottom-width: 3px;
  border-radius: 10px;
  background: #fffdf5;
  color: var(--ink-0);
}
.pw-row input:focus-visible { outline: none; box-shadow: var(--focus); }

/* keeps the chooser badge centered where Startseite used to balance it */
.g-top-spacer { flex: 0 0 8rem; }

/* the shown object as a photo bubble on the person's side */
.bubble-photo { padding: 0.4rem; background: var(--paper-0); }
.bubble-photo img {
  display: block;
  width: min(48vw, 220px);
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: 12px;
}
body[data-view="2d"] .bubble-photo {
  background: #fff;
  border: 2px solid var(--g-band, #dde4cf);
}

/* in 2D the photo bubble IS the projector — the roll-down canvas retires */
body[data-view="2d"] #mobile-leinwand { display: none; }
