/* ---- base ---- */
* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
  font-family: "Jua", "Segoe UI", sans-serif;
  -webkit-user-select: none;
  user-select: none;
}

html, body { height: 100%; }
input, textarea { user-select: text; }

/* The `hidden` attribute has to win.
   The UA stylesheet sets [hidden] { display: none }, but that is a single
   attribute selector and any class rule setting `display` outruns it: a
   .gate-screen with display:flex stayed on screen while hidden, drawn
   underneath the glossary. Everything in this file that hides an element
   uses the attribute, so it is stated once here at the top instead of being
   guarded rule by rule. */
[hidden] { display: none !important; }

:link, :visited { color: var(--brand-ink); }
a:hover { text-decoration: none; }

button {
  cursor: pointer;
  border: none;
  background: none;
  color: inherit;
}
button:disabled { cursor: not-allowed; opacity: 0.6; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

/* ---- brand colour tokens (7 swatches) ---- */
:root,
:root[data-color-theme="classic"] {
  --brand: #ccffcc;
  --brand-rgb: 204, 255, 204;
}
:root[data-color-theme="not-green-1"] { --brand: #ffcccc; --brand-rgb: 255, 204, 204; }
:root[data-color-theme="not-green-2"] { --brand: #ccccff; --brand-rgb: 204, 204, 255; }
:root[data-color-theme="not-green-3"] { --brand: #ffffcc; --brand-rgb: 255, 255, 204; }
:root[data-color-theme="not-green-4"] { --brand: #ffccff; --brand-rgb: 255, 204, 255; }
:root[data-color-theme="not-green-5"] { --brand: #ccffff; --brand-rgb: 204, 255, 255; }
:root[data-color-theme="really-light-green"] { --brand: #ffffff; --brand-rgb: 255, 255, 255; }

/* ---- light / dark surface tokens ---- */
:root,
:root[data-mode="light"] {
  --bg: #eef2f0;
  --surface: rgba(255, 255, 255, 0.55);
  --surface-strong: rgba(255, 255, 255, 0.78);
  --surface-border: rgba(255, 255, 255, 0.65);
  --ink: #121815;
  --muted: #5b665f;
  --shadow: 0 10px 30px rgba(20, 40, 30, 0.10);
  --brand-ink: #1f6b3d;
  --ok: #0f7234;
  --warn: #a24b08;
  --busy: #627288;
  --error: #b91c1c;
}

:root[data-mode="dark"] {
  --bg: #0c100e;
  --surface: rgba(255, 255, 255, 0.06);
  --surface-strong: rgba(255, 255, 255, 0.11);
  --surface-border: rgba(255, 255, 255, 0.14);
  --ink: #eef2ef;
  --muted: #9aa7a0;
  --shadow: 0 10px 34px rgba(0, 0, 0, 0.5);
  --brand-ink: #bff5cf;
  --ok: #4ade80;
  --warn: #fbbf24;
  --busy: #94a3b8;
  --error: #fa9696;
}

/* Same in both modes: brand tints are pale whatever the mode. */
:root {
  --on-brand: #121815;
  /* Brand-derived fills. Any surface that tracked the brand swatch before
     still tracks it, in both modes. Text on these is always --on-brand. */
  --brand-fill: color-mix(in srgb, var(--brand) 55%, var(--surface-strong));
  --brand-fill-strong: color-mix(in srgb, var(--brand) 75%, var(--surface-strong));
  /* Secondary text on --surface-strong. Plain --muted only reaches 3.6:1
     there in dark mode, since the strong surface lightens the backdrop. */
  --muted-strong: color-mix(in srgb, var(--ink) 70%, transparent);
}

/* flat, static colour derived from theme, no gradients */
body {
  background-color: color-mix(in srgb, var(--brand) 10%, var(--bg));
  color: var(--ink);
  min-height: 100vh;
  overflow-x: hidden;
  transition: background-color 0.25s ease, color 0.25s ease;
}

/* ---- glass primitive ---- */
.glass {
  background: var(--surface);
  backdrop-filter: blur(18px) saturate(150%);
  -webkit-backdrop-filter: blur(18px) saturate(150%);
  border: 1px solid var(--surface-border);
  border-radius: 20px;
  box-shadow: var(--shadow);
}

/* ---- icon button (theme trigger, modal close) ---- */
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 14px;
  background: var(--surface-strong);
  border: 1px solid var(--surface-border);
  color: var(--ink);
  transition: transform 0.15s ease, background 0.15s ease;
}
.icon-btn:hover { transform: translateY(-1px); }
.icon-btn svg { width: 20px; height: 20px; }
.icon-btn.small { width: 34px; height: 34px; }
.icon-btn.small svg { width: 16px; height: 16px; }

/* ---- modal shell ---- */
.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  background: rgba(10, 15, 12, 0.35);
  padding: 12px;
  opacity: 1;
  visibility: visible;
  transition: opacity 0.2s ease, visibility 0s linear 0s;
}
.modal-backdrop.hidden {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.18s ease, visibility 0s linear 0.18s;
}

@media (min-width: 640px) {
  .modal-backdrop { align-items: center; }
}

.modal {
  width: 100%;
  max-width: 420px;
  max-height: 85vh;
  overflow-y: auto;
  padding: 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  background: var(--surface-strong);
  opacity: 1;
  transform: translateY(0) scale(1);
  transition: transform 0.22s cubic-bezier(0.2, 0.8, 0.2, 1), opacity 0.18s ease;
}
.modal-backdrop.hidden .modal {
  opacity: 0;
  transform: translateY(14px) scale(0.97);
}

.modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.modal-head h2 { font-size: 1.1rem; color: var(--brand-ink); }

/* Section labels inside the modal: "Mode", "Brand colour". */
.modal-section-label {
  font-size: 0.85rem;
  color: var(--muted);
  margin-top: 4px;
}

body.modal-open { overflow: hidden; }

/* ---- mode toggle ---- */
.mode-toggle {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 6px;
  padding: 4px;
  border-radius: 14px;
  background: var(--surface);
}
.mode-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 8px;
  border-radius: 10px;
  font-size: 0.85rem;
  color: var(--muted);
  transition: background 0.15s ease, color 0.15s ease;
}
.mode-btn svg { width: 16px; height: 16px; }
.mode-btn.active {
  background: var(--brand-fill);
  color: var(--on-brand);
}

/* Time based mode only. Light and dark stay side by side and the third
   spans the row beneath them: two equal columns would put the longer label
   in a box too narrow to read at 320px, and the full width row also signals
   this is a different kind of choice, a rule for picking a mode rather than
   a mode. */
.mode-btn-wide { grid-column: 1 / -1; }
.mode-note {
  margin-top: 0.5rem;
  font-size: 0.85rem;
  color: var(--muted);
}

/* ---- swatch grid ---- */
.swatch-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
}
.swatch {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px;
  border-radius: 14px;
  background: var(--surface);
  border: 1px solid var(--surface-border);
  font-size: 0.78rem;
  text-align: left;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
/* Ringed in its own colour, plus a containment ring. On a light modal the
   pale swatches reach only 1:1 against the surface on their own, so the
   outer ring is what actually carries the active state, at 3.4:1. */
.swatch.active {
  border-color: var(--swatch-color);
  box-shadow:
    0 0 0 2px var(--swatch-color),
    0 0 0 3px color-mix(in srgb, var(--ink) 50%, transparent);
}
.swatch-dot {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--swatch-color);
  border: 1px solid color-mix(in srgb, var(--ink) 30%, transparent);
  flex-shrink: 0;
}

/* ---- buttons ---- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 10px 16px;
  border-radius: 12px;
  font-size: 0.9rem;
  border: 1px solid var(--surface-border);
  background: var(--surface-strong);
  color: var(--ink);
  transition: transform 0.15s ease, background 0.15s ease;
}
.btn:hover:not(:disabled) { transform: translateY(-1px); }
.btn-primary {
  background: var(--brand-fill);
  color: var(--on-brand);
}
.btn-primary:hover:not(:disabled) { background: var(--brand-fill-strong); }
.btn-quiet {
  background: transparent;
  border-color: transparent;
  color: var(--muted-strong);
}

/* ---- update bar ---- */
.update-notice {
  background: color-mix(in srgb, var(--brand) 12%, var(--surface-strong));
  border-bottom: 1px solid var(--surface-border);
  color: var(--ink);
  font-size: 0.875rem;
}

.update-notice-inner {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  max-width: 72rem;
  margin: 0 auto;
  padding: 0.5rem 1rem;
  /* Under the notch on a phone, where the bar is the topmost thing on screen. */
  padding-top: max(0.5rem, env(safe-area-inset-top));
}

.update-notice p { flex: 1 1 auto; min-width: 0; }
.update-notice .btn {
  flex: none;
  padding: 6px 12px;
  font-size: 0.85rem;
}

@media (max-width: 480px) {
  .update-notice-inner { flex-wrap: wrap; }
  .update-notice p { flex-basis: 100%; }
}

/* ---- layout ---- */
.wrap {
  max-width: 720px;
  margin: 0 auto;
  padding: 14px;

  /* Everything stacked above and below the gate card: the topbar and its
     margin, this padding top and bottom, and the footer with its margin.
     .gate-screen subtracts it so the card centres in what is actually left
     rather than in a viewport it does not have all of. Kept next to the
     padding it depends on, and overridden with it at the breakpoint. */
  --chrome-h: 118px;
}

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 14px;
}
.topbar h1 {
  font-size: 1.15rem;
  color: var(--brand-ink);
  line-height: 1.2;
}
.topbar-actions { display: flex; gap: 8px; }

/* ---- gate ---- */

/* The default view: the passcode card centred in what is left of the
   viewport under the top bar, rather than sitting against it. The topbar
   is roughly 42px plus its 14px margin, and .wrap adds 14px top and
   bottom, which is the 84px taken off here. */
/* The topbar and .wrap's own padding are already in the flow above this, so
   the height to fill is what is left of the viewport, measured from where
   this box starts. Subtracting a guessed 84px from 100vh instead overflows
   the page by exactly the padding that was guessed wrong, which is what a
   stray second scroll screen at the bottom of the gate was. */
.gate-screen {
  min-height: calc(100dvh - var(--chrome-h, 70px));
  display: flex;
  align-items: center;
  justify-content: center;
}

/* dvh is not everywhere; vh is the fallback and is close enough, since this
   only decides where a card sits vertically. */
@supports not (height: 100dvh) {
  .gate-screen { min-height: calc(100vh - var(--chrome-h, 70px)); }
}

.gate {
  width: 100%;
  max-width: 340px;
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: center;
  text-align: center;
}

/* The field and its reveal button share one rounded box. */
.field {
  position: relative;
  width: 100%;
}
.field .code-input { padding-right: 46px; }

.reveal-btn {
  position: absolute;
  top: 50%;
  right: 6px;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 10px;
  color: var(--muted-strong);
  transition: color 0.15s ease, background 0.15s ease;
}
.reveal-btn:hover { color: var(--ink); }
.reveal-btn svg { width: 18px; height: 18px; }
.reveal-btn:focus-visible {
  outline: 2px solid var(--brand-ink);
  outline-offset: 2px;
}
.gate-icon {
  display: inline-flex;
  color: var(--brand-ink);
}
.gate-icon svg { width: 32px; height: 32px; }
.gate h2 { font-size: 1.05rem; color: var(--brand-ink); }
.gate p { font-size: 0.9rem; color: var(--muted); }

.gate-form { display: flex; flex-direction: column; gap: 10px; }

.code-input {
  width: 100%;
  padding: 12px 14px;
  border-radius: 14px;
  border: 1px solid var(--surface-border);
  background: var(--surface-strong);
  color: var(--ink);
  font-size: 1.1rem;
  letter-spacing: 0.08em;
  text-align: center;
}
.code-input::placeholder {
  color: var(--muted-strong);
  opacity: 1;
  letter-spacing: normal;
}
.code-input:focus {
  outline: 2px solid var(--brand-ink);
  outline-offset: 2px;
}

.gate-row { display: flex; gap: 8px; align-items: center; }
.gate-row .btn { flex: 1 1 auto; }
.gate-row .icon-btn { flex: none; }

.gate-error {
  font-size: 0.85rem;
  color: var(--error);
  background: color-mix(in srgb, var(--error) 14%, transparent);
  padding: 8px 12px;
  border-radius: 12px;
}

.hint-code {
  font-size: 0.8rem;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--surface-border);
  border-radius: 12px;
  padding: 10px;
  word-break: break-all;
  user-select: text;
}

/* ---- glossary ---- */
.search-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 4px 4px 12px;
  border-radius: 14px;
  background: var(--surface-strong);
  border: 1px solid var(--surface-border);
  margin-bottom: 12px;
}
.search-row .search-icon {
  display: inline-flex;
  color: var(--muted-strong);
  flex: none;
}
.search-row .search-icon svg { width: 18px; height: 18px; }
.search-input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 10px 8px;
  border: none;
  background: none;
  color: var(--ink);
  font-size: 0.95rem;
}
.search-input:focus { outline: none; }
.search-input::placeholder { color: var(--muted-strong); opacity: 1; }

.source-note {
  font-size: 0.85rem;
  color: var(--muted);
  margin-bottom: 10px;
}

.entry-list { list-style: none; display: grid; gap: 10px; }

/* Two columns once there is room for them. A glossary is a lookup table, and
   one entry per row down the middle of a wide screen wastes the width and
   makes the list longer to scan than it needs to be. */
@media (min-width: 860px) {
  .wrap { max-width: 1040px; }
  .entry-list { grid-template-columns: repeat(2, 1fr); align-items: start; }
}
.entry { padding: 14px 16px; }
.entry-code {
  font-size: 1.05rem;
  color: var(--brand-ink);
  letter-spacing: 0.06em;
}
.entry-term { font-size: 0.95rem; color: var(--ink); }
.entry-note {
  margin-top: 6px;
  font-size: 0.85rem;
  color: var(--muted);
  line-height: 1.45;
}

.entry-empty {
  font-size: 0.9rem;
  color: var(--muted);
  padding: 18px;
  text-align: center;
}

.foot {
  margin-top: 18px;
  font-size: 0.8rem;
  color: var(--muted);
  text-align: center;
}

@media (max-width: 480px) {
  .swatch-grid { grid-template-columns: 1fr; }
  /* 8px less padding than above, so the chrome allowance drops with it. */
  .wrap { padding: 10px; --chrome-h: 110px; }
}
