/*
 * Sauron's look, in ONE place (13 Oct 2026).
 *
 * Khai: "I need a softer feeling UI in terms of colour, font and font size."
 * Chosen from three looks shown side by side: WARM LIGHT -- cream background,
 * white cards, warm dark text, terracotta accent -- in Inter, with 15px body
 * text and nothing smaller than 13px.
 *
 * Every page loads this BEFORE its own <style>, and pages use these variables
 * rather than colour codes, so the next change to the look is made here once.
 * Each page used to carry its own copy of the colours.
 *
 * CONTRAST, MEASURED (WCAG ratio against white; 4.5 is the floor for small
 * text): text 14.3, muted 5.5, accent 4.6 (and white text on accent buttons
 * 4.6), error 6.5, success 5.1. The look shown had a lighter grey (4.1) and
 * terracotta (3.6) that fell short, so both were darkened a step.
 *
 * Inter is served from /vendor/fonts, never a font CDN: nothing on these pages
 * loads from a third party (see CLAUDE.md, "Every page is built for the load").
 * SIL Open Font License, alongside the files.
 */

@font-face { font-family: 'Inter'; font-style: normal; font-weight: 400; font-display: swap; src: url('/vendor/fonts/inter-latin-400-normal.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 500; font-display: swap; src: url('/vendor/fonts/inter-latin-500-normal.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 600; font-display: swap; src: url('/vendor/fonts/inter-latin-600-normal.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-style: normal; font-weight: 700; font-display: swap; src: url('/vendor/fonts/inter-latin-700-normal.woff2') format('woff2'); }

:root {
  /* Surfaces */
  --bg: #f6f2ec;            /* cream page */
  --surface: #ffffff;       /* cards */
  --surface-hover: #f1ebe2;
  --border: #e5ddd1;

  /* Text */
  --text: #2e2a25;
  --text-muted: #6f685f;

  /* Accent: terracotta */
  --accent: #b0602a;
  --accent-dim: #934e20;    /* hover / pressed */
  --accent-soft: rgba(176, 96, 42, 0.10);
  --on-accent: #ffffff;     /* text on an accent fill */

  /* States */
  --error: #b3261e;
  --error-soft: rgba(179, 38, 30, 0.08);
  --success: #2f7d4a;
  --success-soft: rgba(47, 125, 74, 0.10);
  --warn: #8a6100;
  --warn-soft: rgba(138, 97, 0, 0.10);
  --info: #3b6fc4;
  --info-soft: rgba(59, 111, 196, 0.10);
  --teal-ink: #1f6f68;      /* a number beside a teal bar, on the page */

  /* Chat */
  --user-bg: #f3e6d9;       /* the person's own message: a warm tint */
  --assistant-bg: #ffffff;
  --bubble: #eef4ee;

  /* Overlays and lines on a light page */
  --hairline: rgba(46, 42, 37, 0.08);
  --shade: rgba(46, 42, 37, 0.04);
  --scrim: rgba(46, 42, 37, 0.35);
  --shadow: 0 6px 24px rgba(46, 42, 37, 0.12);

  --radius: 12px;
  --font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;

  color-scheme: light;
}

/*
 * DARK, the same warm family at night (Khai, 13 Oct 2026: "you should have a
 * dark mode"). It follows each device's own light/dark setting, and the moon
 * button in the menu overrides it per browser (sauron.theme). The small script
 * at the top of every page sets data-theme before anything draws, so there is
 * never a flash of the wrong one -- and why there is ONE selector here, not a
 * media query copy of every rule.
 *
 * Measured against the dark surface (WCAG): text 12.7, muted 6.0, accent 6.5,
 * error 6.4, success 7.5; chart series at least 3:1. The accent is lighter in
 * the dark, so text ON it turns dark (--on-accent), not white.
 */
:root[data-theme="dark"] {
  --bg: #1c1916;
  --surface: #262220;
  --surface-hover: #312c28;
  --border: #3e3732;
  --text: #ece6dd;
  --text-muted: #a89f94;
  --accent: #e5925a;
  --accent-dim: #c9783f;
  --accent-soft: rgba(229, 146, 90, 0.14);
  --on-accent: #1c1916;
  --error: #f2877c;
  --error-soft: rgba(242, 135, 124, 0.12);
  --success: #74c48d;
  --success-soft: rgba(116, 196, 141, 0.12);
  --warn: #e3b45a;
  --warn-soft: rgba(227, 180, 90, 0.12);
  --info: #86adf0;
  --info-soft: rgba(134, 173, 240, 0.12);
  --teal-ink: #6cc3b8;
  --user-bg: #3a2c22;
  --assistant-bg: #262220;
  --bubble: #22302a;
  --hairline: rgba(255, 255, 255, 0.08);
  --shade: rgba(255, 255, 255, 0.04);
  --scrim: rgba(0, 0, 0, 0.55);
  --shadow: 0 6px 24px rgba(0, 0, 0, 0.45);
  color-scheme: dark;
}

/*
 * Charts are stored as drawings with their colours written in (chart-svg.ts),
 * so on a dark page their text and lines would vanish. CSS outranks an SVG's
 * own colour attributes, so these repaint exactly the renderer's ink, axis and
 * grid colours -- old stored charts included, since relightChart() maps them
 * to the same values. The series colours read on both.
 */
:root[data-theme="dark"] svg [fill="#2e2a25"] { fill: var(--text); }
:root[data-theme="dark"] svg [fill="#6f685f"] { fill: var(--text-muted); }
:root[data-theme="dark"] svg [stroke="#6f685f"] { stroke: var(--text-muted); }
:root[data-theme="dark"] svg [stroke="#e5ddd1"] { stroke: var(--border); }
:root[data-theme="dark"] svg [fill="#8a6100"] { fill: var(--warn); }

html { -webkit-text-size-adjust: 100%; }
body {
  font-family: var(--font);
  font-size: 15px;
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
}
/* hidden means hidden, whatever display rule an element also has. One rule
   here for every page (pages.test.ts explains the bug it prevents). */
[hidden] { display: none !important; }

/* Form controls do not inherit the font by default. */
button, input, select, textarea { font-family: inherit; }
/*
 * Drop-downs, everywhere. Most pages styled their inputs and never their
 * <select>s, which drew as the browser's default -- a hard black outline in
 * the middle of a soft page. A page's own rule still wins where it has one.
 */
select {
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 4px 8px;
  font-size: inherit;
  accent-color: var(--accent);
}
select:focus { outline: none; border-color: var(--accent); }

/*
 * On a phone the links move under the title when they do not fit beside it,
 * rather than squeezing the title into a column of single words or running
 * off the edge. Inter at 15px is wider than the old 14px system font, and an
 * owner sees five links.
 */
/* (The header on phones is laid out with the menu below; see header.site-header.) */

/*
 * The Eye on its tower (Khai, 13 Oct 2026): the sign-in page, and the chat and
 * planner before the first question. A 10-second silent loop, generated with
 * Higgsfield: the beam swings left to right and the second half is the first
 * played backwards, so it ends where it begins. 118 KB as WebM, 216 KB as MP4.
 *
 * Muted and playsinline are what let a phone autoplay it at all; iOS refuses
 * otherwise. The still behind it is the first frame, so nothing jumps while the
 * video loads, and it is all that shows for anyone whose phone asks for
 * reduced motion. The round mask fades its edges into the page.
 */
.sauron-watch {
  width: min(220px, 62vw);
  aspect-ratio: 1;
  margin: 0 auto 14px;
  background: url(/brand/sauron-watch.jpg) center / cover no-repeat;
  -webkit-mask-image: radial-gradient(circle, #000 58%, transparent 71%);
  mask-image: radial-gradient(circle, #000 58%, transparent 71%);
}
.sauron-watch video { display: block; width: 100%; height: 100%; object-fit: cover; }
@media (prefers-reduced-motion: reduce) {
  .sauron-watch video { display: none; }
}

/*
 * The Eye at work (/eye-busy.js): glances left, right and back, and blinks.
 * Two cycles of different lengths, so the blink lands on a different glance
 * each time rather than repeating like a metronome. Translations are in the
 * logo's own units; 140 tucks the pupil just under the flames.
 */
.eye-busy { display: inline-block; vertical-align: middle; flex-shrink: 0; overflow: visible; }
.eye-busy .eb-pupil { animation: eb-look 3.4s ease-in-out infinite; }
.eye-busy .eb-lids { transform-box: fill-box; transform-origin: center; animation: eb-blink 4.3s ease-in-out infinite; }
.eye-busy.long .eb-pupil { animation-duration: 1.9s; }
@keyframes eb-look {
  0%, 10% { transform: translateX(0); }
  25%, 40% { transform: translateX(-140px); }
  58%, 72% { transform: translateX(140px); }
  88%, 100% { transform: translateX(0); }
}
@keyframes eb-blink {
  0%, 88%, 100% { transform: scaleY(1); }
  92% { transform: scaleY(0.08); }
  95% { transform: scaleY(1); }
}
@media (prefers-reduced-motion: reduce) {
  .eye-busy .eb-pupil, .eye-busy .eb-lids { animation: none; }
}

/*
 * Bigger targets on a computer (Khai, 13 Oct 2026: "make the buttons bigger
 * and easier to click"). Measured before: the menu links were 19-23 px tall
 * with no padding, so a click had to land on the letters themselves.
 *
 * Only where there is a mouse -- (hover: hover) and (pointer: fine) -- so
 * phones, which size their own touch targets, are untouched. :where() keeps
 * these at zero specificity, so a page that sizes a particular button on
 * purpose still wins; only the floor is raised. Buttons centre their text
 * vertically by themselves, so a taller minimum never misaligns a label.
 */
@media (hover: hover) and (pointer: fine) {
  .site-nav a { padding: 9px 10px; }
  .site-nav a:hover { background: var(--surface-hover); color: var(--text); }
  :where(button, .btn, input[type=submit]) { min-height: 40px; }
  :where(select) { min-height: 36px; }
  :where(.btn-small, .teach-btn, .report-link, .report-btn, .chip, .export-chip) { min-height: 34px; }
  :where(button, .btn, a, select, summary) { cursor: pointer; }
  /* A × inside a tag or row is part of that tag, not a button of its own:
     raising it to 40 px swelled every venue tag on the users list. */
  :where(.vx, .fremove, .ask-close) { min-height: 0; }
}

/* The count on the "Weekly Recommends" menu link (/brief-badge.js). */
.nav-badge {
  display: inline-block;
  min-width: 18px;
  margin-left: 5px;
  padding: 1px 6px;
  border-radius: 9px;
  background: var(--accent);
  color: var(--on-accent);
  font-size: 12px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
  vertical-align: 1px;
}

/*
 * The one menu (every page carries the same markup; pages.test.ts checks).
 * Styled here so no page can size or space it differently -- the 14 px on
 * one page and 15 px on the next was half of why it shuffled. Same weight for
 * the active link, so moving between pages never changes a link's width.
 */
header nav.site-nav {
  margin-left: auto;
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  align-items: center;
  gap: 2px 4px;
  font-size: 15px;
}
header nav.site-nav a {
  color: var(--text-muted);
  text-decoration: none;
  line-height: 1.4;
  padding: 6px 8px;
  border-radius: 8px;
  white-space: nowrap;
  transition: background-color .12s;
}
header nav.site-nav a.active { color: var(--accent); }
header nav.site-nav a[hidden] { display: none; }

/* The header around the menu, the same on every page for the same reason:
   different padding and logo sizes moved the menu a few pixels page to page. */
header.site-header { display: flex; align-items: center; gap: 12px; padding: 14px 20px; }
header.site-header .logo { width: 32px; height: 32px; flex-shrink: 0; margin: 0; }
header.site-header h1 { font-size: 17px; font-weight: 600; line-height: 1.25; margin: 0; }
header.site-header .subtitle { font-size: 13px; line-height: 1.35; color: var(--text-muted); margin: 1px 0 0; }
/*
 * ONE layout at every width (Khai's phone, 13 Oct 2026: the menu broke into
 * rows at different places on different pages). Wide: the menu beside the
 * title, and a long title shortens with an ellipsis rather than pushing the
 * menu down -- its flex basis is 0, so title length never decides the wrap.
 * Narrower than the menu can sit beside a title: the menu takes its own full
 * row, left-aligned, so every page wraps it at exactly the same points.
 */
header.site-header > div:not(.logo) { flex: 1 1 0; min-width: 0; }
header.site-header h1, header.site-header .subtitle { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
header.site-header nav.site-nav { flex: 0 0 auto; }
/* The sidebar's menu button (Query, Plan) is the logo's height, so the title
   row -- and the menu under it -- sits at the same height on every page. */
header.site-header #cs-menu { width: 32px; height: 32px; min-height: 0; }
@media (max-width: 920px) {
  header.site-header { flex-wrap: wrap; row-gap: 6px; column-gap: 0; padding: 12px 16px; }
  header.site-header .subtitle { display: none; }
  header.site-header > div:not(.logo) { margin-left: 12px; }
  header.site-header #cs-menu { margin-right: 10px; }
  /*
   * TWO ROWS ON A PHONE (Khai, 13 Oct 2026: the light/dark switch, then "the
   * cog and logout go to top right"). The logo row carries Settings, the
   * switch and Logout at its right end; the pages fill the row below. The
   * menu's markup is untouched -- the same on every page -- and only laid out
   * differently: `display: contents` lets each link take its own place in the
   * header, and the header's ::after is a full-width break between the rows.
   */
  header.site-header nav.site-nav { display: contents; }
  header.site-header nav.site-nav > * { order: 4; }
  header.site-header nav.site-nav > .nav-icon,
  header.site-header nav.site-nav > .theme-toggle,
  header.site-header nav.site-nav > #logout-link { order: 2; }
  /* The pages' links: no left padding, so whichever link starts a line --
     the first, or one a narrow phone wraps -- lines up with the logo. */
  header.site-header nav.site-nav > a:not(.nav-icon):not(#logout-link) { padding: 6px 12px 6px 0; }
  header.site-header nav.site-nav > .nav-icon, header.site-header nav.site-nav > .theme-toggle { margin-left: 6px; }
  header.site-header nav.site-nav > #logout-link { margin-left: 4px; }
  header.site-header::after { content: ''; order: 3; flex: 0 0 100%; height: 0; }
}

/* Settings (the admin console), owners only: a cog beside the light/dark
   switch, the same round button, rather than a word in the menu. */
header nav.site-nav a.nav-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; min-height: 0; padding: 0; margin-left: 2px;
  border: 1px solid var(--border); border-radius: 50%; background: var(--surface);
}
header nav.site-nav a.nav-icon:hover { color: var(--text); background: var(--surface-hover); }
header nav.site-nav a.nav-icon.active { color: var(--accent); border-color: var(--accent); }
header nav.site-nav a.nav-icon[hidden] { display: none; }
header nav.site-nav a.nav-icon svg { width: 18px; height: 18px; }

/* The light/dark switch in the menu: a moon in the light, a sun in the dark. */
.theme-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; min-height: 0; padding: 0; margin-left: 2px;
  border: 1px solid var(--border); border-radius: 50%;
  background: var(--surface); color: var(--text-muted); cursor: pointer;
}
.theme-toggle:hover { color: var(--text); background: var(--surface-hover); }
.theme-toggle svg { width: 18px; height: 18px; }
.theme-toggle .sun { display: none; }
:root[data-theme="dark"] .theme-toggle .sun { display: block; }
:root[data-theme="dark"] .theme-toggle .moon { display: none; }
/* The tower is painted on cream; at night it sits a little quieter. */
:root[data-theme="dark"] .sauron-watch { filter: brightness(0.88); }

/* "Add Sauron to your home screen" (/install-prompt.js): a card along the
   bottom of a phone screen, offered once. */
.install-offer {
  position: fixed; left: 12px; right: 12px; bottom: calc(12px + env(safe-area-inset-bottom, 0px)); z-index: 80;
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px 12px;
  background: var(--surface); color: var(--text); border: 1px solid var(--border);
  border-radius: 14px; padding: 12px 14px; box-shadow: var(--shadow); font-size: 14px; line-height: 1.4;
}
.install-offer img { border-radius: 10px; flex-shrink: 0; }
.install-offer .io-text { flex: 1 1 180px; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.install-offer .io-text strong { font-size: 15px; }
.install-offer .io-text span { color: var(--text-muted); }
.install-offer .io-text svg { vertical-align: -3px; color: var(--accent); }
.install-offer .io-actions { display: flex; gap: 8px; margin-left: auto; }
.install-offer button { border-radius: 8px; padding: 8px 14px; font: inherit; font-weight: 600; cursor: pointer; border: 1px solid var(--border); background: transparent; color: var(--text); }
.install-offer .io-install { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }

/* Show / hide on a password box (/password-reveal.js): an eye inside the
   box's right end, which leaves room for it. */
.pw-wrap { position: relative; display: block; }
.pw-wrap input { padding-right: 48px !important; }
.pw-eye {
  position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; min-height: 0; padding: 0; margin: 0;
  border: 0; border-radius: 8px; background: none; color: var(--text-muted); cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.pw-eye:hover { color: var(--text); }
.pw-eye svg { width: 20px; height: 20px; }

/* Every chart opens full screen (/chart-zoom.js). A chart says so with an
   expand mark in its corner: always shown on a phone, on hover with a mouse. */
.chart-card, .chart, .ask-chart, .zoom-chart { position: relative; cursor: zoom-in; }
.chart-card::after, .chart::after, .ask-chart::after, .zoom-chart::after {
  content: ''; position: absolute; top: 8px; right: 8px; width: 30px; height: 30px;
  border: 1px solid var(--border); border-radius: 8px; pointer-events: none;
  /* Four corner arrows, in the muted ink (repainted for dark below). */
  background: var(--surface) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236f685f' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7'/%3E%3C/svg%3E") center / 16px no-repeat;
}
:root[data-theme="dark"] .chart-card::after, :root[data-theme="dark"] .chart::after,
:root[data-theme="dark"] .ask-chart::after, :root[data-theme="dark"] .zoom-chart::after {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a89f94' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7'/%3E%3C/svg%3E");
}
@media (hover: hover) and (pointer: fine) {
  .chart-card::after, .chart::after, .ask-chart::after, .zoom-chart::after { opacity: 0; transition: opacity .15s; }
  .chart-card:hover::after, .chart:hover::after, .ask-chart:hover::after, .zoom-chart:hover::after { opacity: 1; }
}
@media print { .chart-card::after, .chart::after, .ask-chart::after, .zoom-chart::after { display: none; } }

html.zv-open, html.zv-open body { overflow: hidden; }
#zoom-view {
  position: fixed; inset: 0; z-index: 1000; display: flex; flex-direction: column;
  background: var(--bg);
}
#zoom-view[hidden] { display: none; }
.zv-bar {
  display: flex; align-items: center; gap: 8px; flex-shrink: 0;
  padding: calc(10px + env(safe-area-inset-top, 0px)) 12px 10px;
  border-bottom: 1px solid var(--border); background: var(--surface);
}
.zv-btn {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 40px; height: 40px; min-height: 0; padding: 0 12px;
  border: 1px solid var(--border); border-radius: 20px; background: var(--surface);
  color: var(--text); font: inherit; font-size: 20px; line-height: 1; cursor: pointer;
}
.zv-btn:hover { background: var(--surface-hover); }
.zv-fit { font-size: 15px; }
.zv-close { margin-left: auto; font-size: 24px; }
.zv-hint { display: none; font-size: 13px; color: var(--text-muted); line-height: 1.3; }
@media (orientation: portrait) and (max-width: 600px) { .zv-hint { display: block; flex: 1 1 0; min-width: 0; } }
.zv-scroll { flex: 1 1 auto; overflow: auto; padding: 16px; overscroll-behavior: contain; }
.zv-content {
  box-sizing: border-box; margin: 0 auto; max-width: none;
  background: var(--surface); border: 1px solid var(--border); border-radius: 12px; padding: 16px;
}
.zv-content svg { display: block; width: 100% !important; max-width: none !important; height: auto; }
.zv-content::after { display: none; }
