/* Aunt Harriot — design system.
   Identity: "March Harriet" — the stranger, looking-glass register (see
   AGENT_IDENTITY_REFERENCE.md). Neutral scale is "gloaming" (dusk violet, not
   pure black/white — deliberately not too dark or too bright either register).
   Four named accent ramps carry the Wonderland references without ever
   spelling them out as decoration:
     queen       — Queen of Hearts crimson-magenta, the signature accent
     cheshire    — the grin: jade-teal
     hatter      — tea-party gold, used sparingly (iamoneself already owns amber as ITS signature)
     caterpillar — hookah-smoke periwinkle-violet
   Distinct from david-amaringo's azure/tangerine/verdant/orchid Amazonian set and
   iamoneself's amber-halo signature — same "named full ramp" discipline, different family.
   Toggle mechanic matches the fleet convention: a `.dark`/`.light` class on <html>,
   not prefers-color-scheme alone, persisted to localStorage (see iamoneself's SettingsModal). */

@import url('https://fonts.googleapis.com/css2?family=Bricolage+Grotesque:opsz,wght@12..96,400..800&family=Space+Grotesk:wght@400;500;600;700&family=Space+Mono:wght@400;700&display=swap');

:root {
  /* gloaming — neutral scale, dusk violet */
  --gloaming-950: #150b28;
  --gloaming-900: #1e1138;
  --gloaming-800: #2a1a4c;
  --gloaming-700: #3a2568;
  --gloaming-600: #503488;
  --gloaming-500: #6d48a8;

  /* paper — light-mode neutral, muted parchment, never stark white */
  --paper-100: #efe6d4;
  --paper-50: #f6efe1;
  --paper-ink: #241534;
  --paper-ink-soft: #5b4b74;
  --paper-line: rgba(36, 21, 52, 0.15);

  /* queen — signature accent, crimson-magenta */
  --queen-900: #4d0a2e;
  --queen-700: #93165a;
  --queen-500: #d81f7f;
  --queen-400: #ef4d95;
  --queen-300: #f584bb;
  --queen-100: #fbdcec;

  /* cheshire — jade-teal */
  --cheshire-900: #063f3a;
  --cheshire-700: #0d6e63;
  --cheshire-500: #17a695;
  --cheshire-400: #35d6c0;
  --cheshire-300: #7ee8da;
  --cheshire-100: #d3f7f1;

  /* hatter — tea-party gold, sparing use */
  --hatter-900: #4a2c05;
  --hatter-700: #83500a;
  --hatter-500: #c9860f;
  --hatter-400: #f4bb3d;
  --hatter-300: #f9d685;
  --hatter-100: #fdf0d3;

  /* caterpillar — hookah-smoke periwinkle */
  --caterpillar-900: #1c1f4a;
  --caterpillar-700: #333a82;
  --caterpillar-500: #5c63b8;
  --caterpillar-400: #8b90d6;
  --caterpillar-300: #b6baea;
  --caterpillar-100: #e6e8f8;

  /* glyph-blue — for standalone decorative unicode glyphs specifically (not
     tabler icons, not the footer's unicode, which stays as-is on request) —
     a true sky blue reads as clearly distinct against the violet/purple
     backdrop, unlike anything else in the four accent ramps above */
  --glyph-blue: #38bdf8;
  --glyph-blue-light: #0369a1;

  --font-display: 'Bricolage Grotesque', system-ui, sans-serif;
  --font-body: 'Space Grotesk', system-ui, sans-serif;
  --font-mono: 'Space Mono', ui-monospace, monospace;
}

/* ---- registers: dark (default) vs light, class-driven ---- */
html.dark {
  --bg: var(--gloaming-950);
  --bg-raised: var(--gloaming-900);
  --bg-raised-rgb: 30, 17, 56;
  --bg-inset: var(--gloaming-800);
  --ink: #f3ecff;
  --ink-soft: #c3aee0;
  --line: rgba(243, 236, 255, 0.14);
  --signature: var(--queen-400);
  --glyph: var(--glyph-blue);
}

html.light {
  --bg: var(--paper-100);
  --bg-raised: var(--paper-50);
  --bg-raised-rgb: 246, 239, 225;
  --bg-inset: #e4d9c1;
  --ink: var(--paper-ink);
  --ink-soft: var(--paper-ink-soft);
  --line: var(--paper-line);
  --signature: var(--queen-500);
  --glyph: var(--glyph-blue-light);
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; overflow-x: hidden; }

/* Safety net: a component overflowing its container (long unbroken text,
   a wide diff line, etc.) should clip, not force the whole page to
   scroll sideways. Fix the component too when this trips — this is a
   backstop, not a substitute for the component wrapping properly.
   Set on both html and body: overflow set only on body doesn't reliably
   propagate to the viewport's actual scrolling box in every engine. */
body { overflow-x: hidden; max-width: 100vw; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  line-height: 1.6;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

a { text-decoration: none; color: inherit; }
a:focus-visible, button:focus-visible, summary:focus-visible, [tabindex]:focus-visible {
  outline: 2px solid var(--hatter-400);
  outline-offset: 3px;
}
img { max-width: 100%; }
code { font-family: var(--font-mono); }

/* Baseline bump so Tabler glyphs actually read as icons rather than
   afterthought punctuation — most usages don't set their own size and
   inherit this; a handful of specific selectors override it deliberately
   (hero, page headings) and take precedence via specificity. */
.ti { font-size: 1.6em; vertical-align: -0.16em; }

/* standalone decorative unicode glyphs (𐃏 ⑂ ⌥ ⎇ ⎈ ⎋ ⎘ ⎉ ⎙ ␣ ⎀ ⌘ etc.) — sized
   to match the tabler icons above and colored to actually stand out against
   the violet backdrop. The footer's unicode (branch separators, the git/dev
   glyphs) is explicitly excluded — it already reads well at its current size
   and color, so .statusbar overrides this back down below. */
.hg-glyph { font-size: 1.6em; color: var(--glyph); vertical-align: -0.16em; font-style: normal; }

/* Internal (this site) vs external links get a visibly different color,
   and external links get a trailing icon — so it's clear before you click
   whether you're staying on Harriot's own pages or leaving them. */
a.ext-link, .markdown-body a[target="_blank"] {
  color: var(--hatter-400) !important;
}
html.light a.ext-link, html.light .markdown-body a[target="_blank"] { color: var(--hatter-700) !important; }
a.ext-link .ti-external-link, .markdown-body a[target="_blank"] .ti-external-link {
  font-size: 0.85em; margin-left: 3px; vertical-align: -0.05em;
}

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

/* Same effect as the OS-level media query above, but as an explicit opt-in
   from the settings modal — some visitors want it off without changing their
   whole system preference. */
html.reduce-motion, html.reduce-motion *, html.reduce-motion *::before, html.reduce-motion *::after {
  animation-duration: 0.01ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.01ms !important;
  scroll-behavior: auto !important;
}

/* ============================================================
   The window — every page is framed as one open workspace.
   ============================================================ */

.titlebar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 18px;
  background: var(--bg-raised);
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: 20;
}

.tb-left { display: flex; align-items: center; gap: 10px; min-width: 0; flex: 1 1 auto; }
.tb-right { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }

.titlebar .dots { display: flex; gap: 6px; flex: 0 0 auto; }
.titlebar .dots span {
  width: 10px; height: 10px; border-radius: 50%; display: block; cursor: pointer;
  animation: dot-breathe 3.4s ease-in-out infinite;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.titlebar .dots span:hover { transform: scale(1.35); }
.titlebar .dots .d1 { background: var(--queen-400); animation-delay: 0s; }
.titlebar .dots .d2 { background: var(--hatter-400); animation-delay: 0.5s; }
.titlebar .dots .d3 { background: var(--cheshire-400); animation-delay: 1s; }
.titlebar .dots .d1:hover { box-shadow: 0 0 10px 2px var(--queen-400); }
.titlebar .dots .d2:hover { box-shadow: 0 0 10px 2px var(--hatter-400); }
.titlebar .dots .d3:hover { box-shadow: 0 0 10px 2px var(--cheshire-400); }
@keyframes dot-breathe { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }

.titlebar .filename {
  font-family: var(--font-mono);
  font-size: 0.82rem;
  color: var(--ink-soft);
  min-width: 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.titlebar .filename b { color: var(--ink); font-weight: 700; }

/* Absolutely positioned so tab position is independent of tb-left/tb-right
   content width — .titlebar's `position: sticky` establishes the containing
   block. This is what actually keeps the hamburger pinned right regardless
   of filename length (a 3-column grid track was tried first and still let a
   non-shrinking filename force everything wide — flexbox + this is the fix). */
.tabs {
  display: flex;
  gap: 2px;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
}

.tabs a {
  font-size: 0.85rem;
  padding: 7px 16px;
  color: var(--ink-soft);
  border-radius: 8px 8px 0 0;
  white-space: nowrap;
  border-bottom: 2px solid transparent;
}
.tabs a:hover { color: var(--ink); }
.tabs a[aria-current] {
  color: var(--ink);
  background: var(--bg);
  border-bottom-color: var(--signature);
}

.settings-btn, .hamburger {
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--ink-soft);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.05rem;
}
.settings-btn:hover, .hamburger:hover { color: var(--ink); border-color: var(--signature); }
/* Hamburger is a real "all pages" menu now, shown at every width right next
   to Settings — the center tab bar stays the 3 main pages only, this is the
   quick-access-to-everything-else button. */

.tabs a .ti, .mobile-menu a .ti { margin-right: 5px; }

/* Overlays the page instead of pushing content down — position:sticky
   reserves its own box height in normal flow, which isn't an overlay at all;
   fixed positioning is what actually floats it above everything below. */
.mobile-menu {
  display: none;
  flex-direction: column;
  gap: 2px;
  padding: 8px 18px 14px;
  background: var(--bg-raised);
  border-bottom: 1px solid var(--line);
  position: fixed;
  top: 55px;
  left: 0; right: 0;
  max-height: calc(100vh - 55px);
  overflow-y: auto;
  z-index: 50;
  box-shadow: 0 20px 40px -10px rgba(0,0,0,0.4);
}
.mobile-menu.open { display: flex; }
.mobile-menu a {
  padding: 10px 10px;
  color: var(--ink-soft);
  font-size: 0.95rem;
  border-radius: 6px;
}
.mobile-menu a[aria-current] { color: var(--ink); background: var(--bg); }
.mobile-menu .menu-divider {
  margin: 8px 0 2px; padding-top: 8px; border-top: 1px solid var(--line);
  font-size: 0.72rem; font-family: var(--font-mono); color: var(--ink-soft); text-transform: uppercase;
}
/* .settings-btn's base rule fixes it at a 34x34 square for the icon-only desktop
   button — reusing the class here with a text label needs a full override, not
   just alignment tweaks, or the label overflows that tiny fixed box. */
.mobile-menu .settings-btn {
  width: 100%; height: auto; justify-content: flex-start; gap: 8px;
  padding: 10px 10px; margin-top: 8px; border: none; border-radius: 6px;
  font-family: var(--font-body); font-size: 0.95rem; color: var(--ink-soft);
}
.mobile-menu .settings-btn:hover { color: var(--ink); border-color: transparent; }

/* Below this width the centered 3-page tab bar would overlap the title-bar's
   own content — settings + hamburger stay visible at every width, this only
   hides the redundant center tabs (the hamburger's menu covers the same 3
   pages plus everything else). */
@media (max-width: 720px) {
  .tabs { display: none; }
}

/* ============================================================
   Generic modal — used by the settings modal (every page) and
   the sign-in wizard (workspace.html).
   ============================================================ */
.hg-modal-overlay {
  display: none;
  position: fixed; inset: 0; z-index: 100;
  background: rgba(5, 3, 10, 0.6);
  align-items: center; justify-content: center;
  padding: 20px;
}
.hg-modal-overlay.open { display: flex; }
.hg-modal {
  background: var(--bg-raised);
  border: 1px solid var(--line);
  border-radius: 12px;
  max-width: 420px;
  width: 100%;
  max-height: 85vh;
  overflow-y: auto;
  box-shadow: 0 20px 60px -20px rgba(0,0,0,0.5);
}
.hg-modal-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 18px; border-bottom: 1px solid var(--line);
}
.hg-modal-head h2 { font-family: var(--font-display); font-size: 1.1rem; margin: 0; display: flex; align-items: center; gap: 8px; }
.hg-modal-close {
  width: 28px; height: 28px; border-radius: 6px; border: 1px solid var(--line);
  background: transparent; color: var(--ink-soft); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.hg-modal-close:hover { color: var(--ink); border-color: var(--signature); }
.hg-modal-body { padding: 18px; }

.hg-setting-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; padding: 12px 0; border-bottom: 1px solid var(--line);
}
.hg-setting-row:last-child { border-bottom: none; }
.hg-setting-row .label { display: flex; align-items: center; gap: 10px; font-size: 0.92rem; }
.hg-setting-row .label .sub { display: block; font-size: 0.78rem; color: var(--ink-soft); font-weight: 400; }
.hg-setting-row .label b { font-weight: 600; }

.hg-switch {
  position: relative; width: 44px; height: 26px; border-radius: 999px;
  border: 1px solid var(--line); background: var(--bg); cursor: pointer; flex: 0 0 auto;
  transition: background 0.35s ease, border-color 0.35s ease;
  overflow: hidden;
}
.hg-switch .knob {
  position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; border-radius: 50%;
  background: var(--ink-soft);
  transition: transform 0.3s cubic-bezier(.34,1.56,.64,1), background 0.3s ease;
  box-shadow: 0 1px 3px rgba(0,0,0,0.3);
}
/* the "color-switching" part: a gradient wash that only becomes visible as
   the switch turns on, rather than a flat single-color fill */
.hg-switch::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit;
  background: linear-gradient(90deg, var(--cheshire-500), var(--signature), var(--hatter-400));
  opacity: 0; transition: opacity 0.35s ease;
}
.hg-switch.on::before { opacity: 1; }
.hg-switch.on { border-color: transparent; }
.hg-switch.on .knob { transform: translateX(18px); background: var(--gloaming-950); }
html.light .hg-switch.on .knob { background: var(--paper-50); }
.hg-switch[disabled] { opacity: 0.4; cursor: not-allowed; }

.hg-badge-soon {
  font-family: var(--font-mono); font-size: 0.65rem; padding: 1px 6px; border-radius: 4px;
  background: var(--bg-inset); color: var(--ink-soft); border: 1px solid var(--line);
}

/* force-mobile-view (desktop browser, previewing mobile): constrain the page
   to a phone-width column. Wide enough that the footer's "main - home -
   terminal - docs" segment doesn't wrap to two lines. */
html.force-mobile body {
  max-width: 460px; margin: 0 auto; border-left: 1px solid var(--line); border-right: 1px solid var(--line);
  box-shadow: 0 0 60px rgba(0,0,0,0.35);
}
html.force-mobile .statusbar { max-width: 460px; left: 50%; right: auto; transform: translateX(-50%); }
html.force-mobile .tabs { display: none; }

/* force-desktop-view (real mobile device, requesting desktop): the meta
   viewport tag itself gets rewritten in JS (site.js) to a fixed wide width —
   that's what actually makes a real phone render the desktop layout. This
   class just re-enables the center tabs to match, since real mobile hides
   them via the @media rule above regardless of what the viewport reports. */
html.force-desktop .tabs { display: flex; }

/* flashing cursor in empty text fields — a small terminal-style affordance.
   Hidden by default; shown only while the field is both empty AND unfocused.
   The moment it's focused, the field has the OS's own real text cursor, so
   ours steps aside rather than blinking alongside it. */
.hg-cursor-field { position: relative; display: block; width: 100%; }
.hg-cursor-field .hg-cursor {
  position: absolute; top: 50%; transform: translateY(-50%); pointer-events: none;
  color: var(--signature); font-family: var(--font-mono); animation: hg-blink 1s steps(1) infinite;
  opacity: 0; transition: opacity 0.15s ease;
}
.hg-cursor-field input:placeholder-shown ~ .hg-cursor { opacity: 1; }
.hg-cursor-field input:focus ~ .hg-cursor { opacity: 0; }
@keyframes hg-blink { 50% { opacity: 0; } }

/* iOS/Android auto-zoom on input focus triggers whenever a focused field's
   font-size is under 16px — this is what was "zooming in on mobile" when the
   chat input auto-focused. Force every real text input to 16px there;
   16px reads identically to the current sizes at normal (non-mobile) widths. */
@media (max-width: 720px) {
  input[type="text"], input[type="email"], input[type="password"] { font-size: 16px !important; }
}

/* traffic-light easter egg toast */
.hg-toast {
  position: fixed; top: 64px; left: 50%; transform: translate(-50%, -10px);
  background: var(--bg-raised); border: 1px solid var(--signature); color: var(--ink);
  padding: 9px 18px; border-radius: 999px; font-size: 0.88rem; font-weight: 600;
  z-index: 200; opacity: 0; transition: opacity 0.25s ease, transform 0.25s ease;
  box-shadow: 0 10px 30px -8px rgba(0,0,0,0.4); pointer-events: none;
  display: flex; align-items: center; gap: 8px; white-space: nowrap;
}
.hg-toast .ti { color: var(--signature); }
.hg-toast.show { opacity: 1; transform: translate(-50%, 0); }
.hg-toast .toast-text::after {
  content: ''; display: inline-block; width: 2px; height: 0.9em; margin-left: 2px;
  background: var(--signature); vertical-align: -0.1em; animation: toast-caret 0.8s step-end infinite;
}
.hg-toast.done .toast-text::after { display: none; }
@keyframes toast-caret { 0%, 100% { opacity: 1; } 50% { opacity: 0; } }
html.reduce-motion .hg-toast .toast-text::after { display: none; }

main { flex: 1 0 auto; padding-bottom: 44px; }

.statusbar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 7px 18px;
  background: var(--bg-raised);
  border-top: 1px solid var(--line);
  color: var(--ink-soft);
  font-size: 0.76rem;
  font-family: var(--font-mono);
  flex-wrap: wrap;
  z-index: 15;
}
.statusbar a { color: var(--ink-soft); text-decoration: underline; text-underline-offset: 2px; }
.statusbar a:hover { color: var(--ink); }
.statusbar a[aria-current] { color: var(--signature); font-weight: 700; text-decoration-style: solid; }
.statusbar .status-left { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; }
.statusbar .branch { color: var(--signature); display: inline-flex; align-items: center; gap: 4px; }
.statusbar .branch-icon { flex: 0 0 auto; }
.statusbar .sep { animation: rainbow-prism 5s linear infinite; }
@keyframes rainbow-prism {
  0%   { color: #ef4d95; }
  20%  { color: #f4bb3d; }
  40%  { color: #35d6c0; }
  60%  { color: #8b90d6; }
  80%  { color: #4fc3f5; }
  100% { color: #ef4d95; }
}
/* reduce-motion already freezes any animation's duration globally (see the
   html.reduce-motion rule near the top) — this just needs a resting color
   for that frozen frame instead of getting stuck wherever the cycle was */
html.reduce-motion .statusbar .sep { color: var(--line); }
