/* ============================================================
   app.css — shared styles for the whole app
   ============================================================ */

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

:root {
  --font: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --radius-sm: 6px;
  --radius-md: 8px;
  --radius-lg: 12px;

  --color-bg:          #ffffff;
  --color-bg-2:        #f8f8f7;
  --color-bg-3:        #f0efec;
  --color-border:      rgba(0,0,0,0.10);
  --color-border-2:    rgba(0,0,0,0.18);
  --color-text:        #1a1a18;
  --color-text-2:      #5a5a56;
  --color-text-3:      #9a9a94;

  --color-green:       #1D9E75;
  --color-green-bg:    #E1F5EE;
  --color-green-text:  #085041;
  --color-amber:       #BA7517;
  --color-amber-bg:    #FAEEDA;
  --color-amber-text:  #412402;
  --color-red:         #A32D2D;
  --color-red-bg:      #FCEBEB;
  --color-red-text:    #501313;
  --color-blue:        #185FA5;
  --color-blue-bg:     #E6F1FB;
  --color-blue-text:   #042C53;

  /* Marketplace for Kids brand (sampled from logo-mfk.png) */
  --mfk-blue:    #0070b0;
  --mfk-blue-dk: #005a8e;
  --mfk-red:     #d92b35;
  --mfk-yellow:  #f5d800;
  --mfk-green:   #10a050;
}

body {
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.5;
  color: var(--color-text);
  background: var(--color-bg-2);
  min-height: 100vh;
}

/* ── Layout ── */
.page-center {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem 1rem;
}

.container {
  max-width: 1024px;
  margin: 0 auto;
  padding: 2rem 1rem;
}

.container-sm {
  max-width: 420px;
  margin: 0 auto;
  padding: 2rem 1rem;
}

/* ── Cards ── */
.card {
  background: var(--color-bg);
  border: 0.5px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: 1.25rem;
  margin-bottom: 1rem;
}

.card-title {
  font-size: 15px;
  font-weight: 500;
  margin-bottom: 0.25rem;
}

.card-sub {
  font-size: 13px;
  color: var(--color-text-2);
  margin-bottom: 1rem;
}

/* ── Forms ── */
.field { margin-bottom: 0.75rem; }

.field label {
  display: block;
  font-size: 12px;
  color: var(--color-text-2);
  margin-bottom: 4px;
}

.field input,
.field select,
.field textarea {
  width: 100%;
  padding: 8px 10px;
  font-size: 14px;
  font-family: var(--font);
  border: 0.5px solid var(--color-border-2);
  border-radius: var(--radius-md);
  background: var(--color-bg);
  color: var(--color-text);
  transition: border-color 0.15s;
}

.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--color-green);
}

.field textarea { resize: vertical; min-height: 64px; }

/* Checkboxes and radios are controls, not text fields. Without this they
   inherit the full-width padded box above and swell into their labels. */
.field input[type="checkbox"],
.field input[type="radio"] {
  width: auto;
  min-width: 0;
  padding: 0;
  margin: 0;
  border: none;
  background: none;
  border-radius: 0;
  flex: none;
}

.form-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}

.form-row.full { grid-template-columns: 1fr; }

/* ── Buttons ── */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 18px;
  font-size: 14px;
  font-family: var(--font);
  font-weight: 500;
  border-radius: var(--radius-md);
  border: 0.5px solid var(--color-border-2);
  background: var(--color-bg);
  color: var(--color-text);
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s;
  text-decoration: none;
}

.btn:hover { background: var(--color-bg-3); }

.btn-primary {
  background: var(--mfk-blue);
  color: white;
  border-color: var(--mfk-blue);
}
.btn-primary:hover { background: var(--mfk-blue-dk); border-color: var(--mfk-blue-dk); }

.btn-sm { padding: 4px 12px; font-size: 12px; }
.btn-danger { color: var(--color-red); border-color: #F09595; background: var(--color-red-bg); }
.btn-warn   { color: var(--color-amber-text); border-color: #EF9F27; background: var(--color-amber-bg); }
.btn-full   { width: 100%; justify-content: center; }

/* ── Semantic action colors ──────────────────────────────────
   Make intent obvious at a glance and read clearly as buttons:
     .btn-add    → green filled  (create / add new)
     .btn-blue   → blue filled   (a second create action beside .btn-add)
     .btn-primary→ blue filled   (edit / save / primary action)
     .btn-delete → red filled    (delete / remove)
   Use the filled variants for primary actions; the soft
   .btn-danger stays available for secondary/inline removes. */
.btn-add {
  background: var(--color-green);
  color: white;
  border-color: var(--color-green);
}
.btn-add:hover { background: var(--color-green-text); border-color: var(--color-green-text); }

/* Blue filled — a create action that sits beside .btn-add and should read
   as a different kind of thing (adding a room next to adding a building). */
.btn-blue {
  background: var(--color-blue-text, #0070b0);
  border-color: var(--color-blue-text, #0070b0);
  color: #fff;
}
.btn-blue:hover { background: #005b8f; border-color: #005b8f; }

/* Looks unavailable but stays clickable, so the click can explain why
   rather than a permanent sentence sitting on the page. */
.btn-muted { opacity: .45; }
.btn-muted:hover { opacity: .6; }

/* Header row above a list: search and filters sit left, the create action
   is pinned to the right edge. Scoped to the toolbar so the many other
   .btn-add buttons inside cards and forms are unaffected. */
.list-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}
.list-toolbar .btn-add { margin-left: auto; }

.btn-delete {
  background: var(--color-red);
  color: white;
  border-color: var(--color-red);
}
.btn-delete:hover { background: var(--color-red-text); border-color: var(--color-red-text); }

/* ── Edit and change ──────────────────────────────────────────
   The third verb, alongside add and delete.

   ADD is green and filled, DELETE is red and filled — both make
   something appear or disappear, and both deserve weight. EDIT changes
   something that is already there. It is the commonest action in the
   admin app and it sits inline, on rows, in headers, several to a
   screen; giving it the same weight as add and delete would make every
   list shout.

   So: blue OUTLINE, never filled. Present, clearly a button, and quiet
   enough to repeat down a list.

     .btn-edit   → blue outline   (edit, change, unlock, reassign)
     .btn-primary→ blue filled    (SAVE — the one confirming action in a
                                   form; there should only ever be one)

   The pairing matters: an Edit button opens a form whose Save is filled
   blue, so the eye goes from outline to filled as the action commits.

   Written out with ad-hoc inline styles before this — the same action
   appeared as plain .btn, .btn-edit, .btn-primary, and .btn-danger on
   four different screens. */
.btn-edit {
  color: var(--mfk-blue);
  border-color: var(--mfk-blue);
  background: var(--color-bg);
  font-weight: 600;
}
.btn-edit:hover { background: #EAF4FA; }


.btn-row {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 1.25rem;
}

/* ── Badges ── */
.badge {
  display: inline-block;
  font-size: 11px;
  font-weight: 500;
  padding: 2px 8px;
  border-radius: 10px;
}

.badge-draft     { background: var(--color-bg-3); color: var(--color-text-2); border: 0.5px solid var(--color-border-2); }
.badge-submitted { background: var(--color-amber-bg); color: var(--color-amber-text); }
.badge-confirmed { background: var(--color-green-bg); color: var(--color-green-text); }
.badge-cancelled { background: var(--color-red-bg);   color: var(--color-red-text); }
.badge-open      { background: var(--color-green-bg); color: var(--color-green-text); }
.badge-closed    { background: var(--color-red-bg);   color: var(--color-red-text); }
.badge-override  { background: var(--color-amber-bg); color: var(--color-amber-text); }
.badge-info      { background: var(--color-blue-bg);  color: var(--color-blue-text); }

/* ── Section labels ── */
.section-label {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--mfk-blue);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin: 0.9rem 0 0.4rem;
}

/* ── Divider ── */
.divider {
  border: none;
  border-top: 0.5px solid var(--color-border);
  margin: 0.75rem 0;
}

/* ── Alerts ── */
.alert {
  padding: 8px 12px;
  border-radius: var(--radius-md);
  font-size: 13px;
  margin-bottom: 0.75rem;
  border: 0.5px solid transparent;
}

.alert-success { background: var(--color-green-bg); color: var(--color-green-text); border-color: #5DCAA5; }
.alert-warn    { background: var(--color-amber-bg); color: var(--color-amber-text); border-color: #EF9F27; }
.alert-error   { background: var(--color-red-bg);   color: var(--color-red-text);   border-color: #F09595; }
.alert-info    { background: var(--color-blue-bg);  color: var(--color-blue-text);  border-color: #85B7EB; }

/* ── Toggle ── */
.toggle-wrap { display: flex; align-items: center; gap: 10px; font-size: 13px; color: var(--color-text-2); }

.toggle {
  position: relative;
  width: 32px;
  height: 18px;
  border-radius: 9px;
  background: var(--color-border-2);
  border: none;
  cursor: pointer;
  padding: 0;
  flex-shrink: 0;
  transition: background 0.2s;
}
.toggle.on  { background: var(--color-green); }
.toggle::after {
  content: '';
  position: absolute;
  top: 2px; left: 2px;
  width: 14px; height: 14px;
  border-radius: 50%;
  background: white;
  transition: left 0.15s;
}
.toggle.on::after { left: 16px; }

/* ── Stepper ── */
.stepper {
  display: flex;
  border: 0.5px solid var(--color-border);
  border-radius: var(--radius-lg);
  overflow: hidden;
  margin-bottom: 1.5rem;
}

.step {
  flex: 1;
  padding: 9px 6px;
  font-size: 11px;
  font-weight: 500;
  font-family: var(--font);
  background: var(--color-bg-3);
  border: none;
  border-right: 0.5px solid var(--color-border);
  cursor: pointer;
  color: var(--color-text-2);
  text-align: center;
  transition: background 0.15s, color 0.15s;
}
.step:last-child { border-right: none; }
.step .step-num  { display: block; font-size: 16px; font-weight: 500; margin-bottom: 1px; }
.step.active     { background: var(--color-bg); color: var(--mfk-blue); box-shadow: inset 0 -3px 0 var(--mfk-blue); }
.step.done       { color: var(--color-green); }

/* ── Nav bar ── */
.navbar {
  background: var(--color-bg);
  border-bottom: 0.5px solid var(--color-border);
  padding: 0.75rem 1.25rem;
  display: flex;
  align-items: center;
  gap: 12px;
}
.navbar-brand { font-size: 14px; font-weight: 500; flex: 1; text-decoration: none; color: var(--color-text); }
.navbar-meta  { font-size: 12px; color: var(--color-text-2); }

/* ── Spinner ── */
.spinner {
  display: inline-block;
  width: 18px; height: 18px;
  border: 2px solid var(--color-border-2);
  border-top-color: var(--color-green);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.loading {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 3rem;
  color: var(--color-text-2);
  font-size: 13px;
}

/* ── Utilities ── */
.text-muted  { color: var(--color-text-2); }
.text-sm     { font-size: 13px; }
.text-xs     { font-size: 11px; }
.text-right  { text-align: right; }
.mt-1        { margin-top: 0.5rem; }
.mt-2        { margin-top: 1rem; }
.flex        { display: flex; }
.flex-center { display: flex; align-items: center; }
.gap-1       { gap: 6px; }
.gap-2       { gap: 12px; }
.flex-1      { flex: 1; }
.hidden      { display: none !important; }

/* ── Global loading overlay (fix #6) ── */
#app-loading-overlay {
  position: fixed; inset: 0; z-index: 2000;
  background: rgba(255,255,255,0.55);
  display: none; align-items: center; justify-content: center;
  backdrop-filter: blur(1px);
}
#app-loading-overlay.show { display: flex; }
#app-loading-overlay .spinner {
  width: 38px; height: 38px; border-radius: 50%;
  border: 3px solid rgba(0,0,0,0.12);
  border-top-color: var(--color-green, #2a7);
  animation: app-spin 0.7s linear infinite;
}
@keyframes app-spin { to { transform: rotate(360deg); } }

/* ── Admin sub-navigation (shared by all admin pages) ── */
.admin-nav { display: flex; gap: 0; border-bottom: 0.5px solid var(--color-border); margin-bottom: 1.5rem; }
.admin-nav a { padding: 8px 16px; font-size: 13px; color: var(--color-text-2); text-decoration: none; border-bottom: 2px solid transparent; }
.admin-nav a:hover { color: var(--color-text); }
.admin-nav a.active { color: var(--color-text); border-bottom-color: var(--color-green); font-weight: 500; }

/* ── System menu (native <details> dropdown in the navbar) ── */
.nav-menu { position: relative; display: inline-block; }
.nav-menu > summary { list-style: none; cursor: pointer; user-select: none; }
.nav-menu > summary::-webkit-details-marker { display: none; }
.nav-menu > summary::marker { content: ""; }
.nav-menu > summary.active { color: var(--color-text); border-color: var(--mfk-blue); }
.nav-menu-caret { font-size: 9px; margin-left: 5px; opacity: .7; }
.nav-menu-list {
  position: absolute; right: 0; top: calc(100% + 6px);
  min-width: 180px; padding: 6px;
  background: #fff; border: 0.5px solid var(--color-border);
  border-radius: var(--radius-md); box-shadow: 0 8px 28px rgba(0,0,0,0.14);
  display: flex; flex-direction: column; z-index: 200;
}
.nav-menu-list a {
  padding: 9px 12px; font-size: 13px; color: var(--color-text);
  text-decoration: none; border-radius: var(--radius-sm); white-space: nowrap;
}
.nav-menu-list a:hover { background: var(--color-blue-bg); }
.nav-menu-list a.active { color: var(--mfk-blue); font-weight: 600; }

/* ── Evaluation question controls (shared by eval.html + volunteer.html,
      styling the markup from js/eval-questions.js) ── */
.rating { display: flex; gap: 8px; flex-wrap: wrap; }
.rating button {
  flex: 1; min-width: 54px; padding: 10px 0;
  border: 1px solid var(--color-border, #e6e8ee); background: #fff;
  border-radius: 9px; font-size: 15px; font-weight: 600; cursor: pointer;
  color: var(--color-text, #1a1a18);
}
.rating button.sel { background: var(--mfk-blue, #0070b0); border-color: var(--mfk-blue, #0070b0); color: #fff; }
.ends { font-size: 11px; color: var(--color-text-2, #9aa3ad); font-weight: 400; }
.yesno { display: flex; gap: 10px; }
.yesno button {
  padding: 9px 22px; border: 1px solid var(--color-border, #e6e8ee);
  background: #fff; border-radius: 9px; font-size: 14px; font-weight: 600; cursor: pointer;
}
.yesno button.sel { background: var(--mfk-blue, #0070b0); border-color: var(--mfk-blue, #0070b0); color: #fff; }




/* ── Marketplace for Kids brand elements ── */
.mfk-stripe {
  height: 4px;
  background: linear-gradient(to right,
    var(--mfk-red) 0 25%, var(--mfk-blue) 25% 50%,
    var(--mfk-yellow) 50% 75%, var(--mfk-green) 75% 100%);
}
.navbar-logo { height: 34px; width: auto; display: block; }
.navbar .navbar-brand { display: flex; align-items: center; gap: 10px; }

/* ── Class letter badge ───────────────────────────────────────
   The letter printed on room signs, guide books, and name badges.
   Rendered by classLetterBadge() in js/utils.js. Defined here once —
   three pages had their own near-identical copies, already drifting. */
.cls-letter {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 20px; border-radius: 4px;
  background: var(--mfk-blue); color: #fff;
  font-size: 11px; font-weight: 700; flex-shrink: 0;
}
.cls-letter.is-activity { background: var(--color-green, #2e8b57); }
/* Holds the column open on a row that has no letter, so names line up. */
.cls-letter.is-empty { background: transparent; }

/* ── Lightbox backdrop ────────────────────────────────────────
   Written out separately on every page before this, with inconsistent
   padding and only some of them scrollable — so a tall modal ran off
   the screen while the PAGE BEHIND scrolled instead.

   align-items:flex-start, not center: a modal taller than the viewport
   centred vertically has its top cut off, and no amount of scrolling
   brings it back. */
.lightbox {
  position: fixed; inset: 0; z-index: 5000;
  display: flex; align-items: flex-start; justify-content: center;
  background: rgba(15,23,42,.55);
  padding: 4vh 16px; overflow: auto;
  -webkit-overflow-scrolling: touch;
}
/* The panel never exceeds the viewport, and scrolls its own body.

   margin:auto does the vertical positioning, not align-items. Auto
   margins absorb whatever free space there is, so a SHORT modal ends up
   centred, while a TALL one has no space to absorb and stays pinned to
   the top where align-items put it — which is what stops its heading
   being scrolled off past the top of the screen. Setting
   align-items:center instead would centre the short ones and clip the
   tall ones. */
.lightbox > * { max-height: 92vh; margin: auto; }

/* Icon-only actions on a dense row: a fixed square so the glyph centres
   regardless of the font's metrics, which padding alone never manages. */
.btn-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; padding: 0;
  font-size: 13px; line-height: 1; flex-shrink: 0;
}

/* An edit action tucked into a heading or a table row, where even an
   outline button is too much furniture. Reads as a link, behaves as a
   button. */
.btn-inline-edit {
  background: none; border: none; padding: 0;
  font: inherit; font-size: 12px; font-weight: 600;
  color: var(--mfk-blue); cursor: pointer;
  text-transform: none; letter-spacing: 0;
}
.btn-inline-edit:hover { text-decoration: underline; }

/* ── Photo permission ─────────────────────────────────────────
   Both states are shown, never one. photo_release defaults to true in
   the database, so the ABSENCE of a marker cannot be read as "no" —
   silence would be the dangerous reading.

   Same icon either way, struck through when permission is refused, so
   the two read as one fact with two values rather than two unrelated
   labels. The slash is drawn rather than relying on an emoji, because
   there is no "no camera" glyph with dependable coverage. */
.photo-ok, .photo-no {
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; line-height: 1; flex-shrink: 0;
}
.photo-ok { opacity: .75; }
.photo-no { position: relative; }
.photo-no::after {
  content: ''; position: absolute; left: -1px; right: -1px; top: 50%;
  height: 2px; background: var(--color-red); border-radius: 1px;
  transform: rotate(-20deg);
  box-shadow: 0 0 0 1px rgba(255,255,255,.9);
}

/* ── Photo permission toggle ──────────────────────────────────
   A labelled toggle rather than a checkbox: the two states have
   different consequences, so both are named rather than one being the
   absence of the other. Defined here because the teacher's registration
   and the admin's student form must offer the same control — a
   checkbox in one and a toggle in the other would be two answers to the
   same question. */
.photo-toggle {
  font-size: 12px; font-weight: 600; padding: 4px 12px; border-radius: 999px;
  cursor: pointer; font-family: var(--font); white-space: nowrap;
  transition: all .12s; border: 1px solid transparent;
}
.photo-toggle.on  { background: var(--color-green-bg); color: var(--color-green-text); border-color: #9ad9c2; }
.photo-toggle.off { background: var(--color-amber-bg); color: var(--color-amber-text); border-color: #efc06a; }
.photo-toggle:disabled { opacity: .7; cursor: default; }
.photo-toggle:not(:disabled):hover { filter: brightness(.96); }
