/* Was an inline <style> block in index.html; moved out so the CSP can be
   strict about style-src. Same rules, same order, nothing re-tuned. */
/* Light. Every text/surface pair the UI renders measures ≥ 4.5:1 (WCAG AA).

   The Warm Paper system. Two full palettes — not one inverted. Light mode
   reads as painted paper (warm ivory bg, deep brown ink, burnt-sienna
   accent); dark mode reads as unlit-glass (warm graphite bg, cream ink,
   amber glow). Neutrals are warm-cast throughout; the earlier Apple system-
   grey palette was blue-cast and read as an internal Apple tool, which is
   exactly the identity we were trying to shed.

   Worst rendered light-mode pair: 4.62:1 (sidebar meta on --side).
   Worst rendered dark-mode pair:  5.97:1 (tertiary on --bg).
   Full contrast measurements live in docs/design.md. */
:root{
  color-scheme:light;
  --bg:#FAF6EC;                     /* warm ivory paper */
  --side:#F1EADB;                   /* toasted paper — recessed under --bg */
  --bubble:#EDE2CC;                 /* question bubble, elevated warm card */
  --ink:#201812;                    /* warm brown-black, 16.2:1 on --bg */
  --ink-2:#5A4A3A;                  /*  7.9:1 */
  --ink-3:#77664F;                  /*  5.1:1 on --bg, 4.6:1 on --side */
  --accent:#A03A10;                 /* burnt sienna — unlit filament, 6.3:1 */
  --accent-bg:rgba(160,58,16,.06);  /* tinted focus panel, ≈ 1.06:1 off page */
  --accent-2:#5C7A48;               /* moss, reserved for secondary emphasis */
  --hair:rgba(46,28,10,.11);
  --hair-2:rgba(46,28,10,.07);
  --hover:rgba(46,28,10,.05);
  --hover-2:rgba(46,28,10,.09);
  --edge:rgba(46,28,10,.25);
  --send-fg:#FAF6EC;                /* inverts with --ink, matches paper */
  --img-ring:rgba(46,28,10,.08);
  --scrim:rgba(20,14,8,.93);
  --lift:0 0 40px rgba(46,28,10,.14);
  /* Three role-based type tokens. Fonts are self-hosted under /fonts/ and
     loaded via /fonts/index.css from index.html — no external requests,
     no CSP change (default-src 'self' covers font-src). Every family has
     a system fallback so a font-src failure still renders a usable page. */
  --sans:'Instrument Sans',-apple-system,BlinkMacSystemFont,Helvetica,Arial,sans-serif;
  --display:'Fraunces',Georgia,'Times New Roman',serif;
  --mono:'IBM Plex Mono',ui-monospace,SFMono-Regular,Menlo,monospace;
}

/* Dark. Not an inversion — each token is re-derived to hold the SAME contrast
   band as its light counterpart, then adjusted for how dark surfaces behave:
     · text is #F1E6D0 (warm cream), never pure white — pure white haloes on
       near-black at these weights AND clashes with the warm-cast neutrals
     · surfaces keep their light-mode relationship: sidebar stays recessed,
       so it goes DARKER than the content panel, not lighter
     · hairlines need more alpha — white separators read weaker than black ones
     · the accent lightens to a warm amber glow; the light-mode ember at
       #A03A10 goes muddy on near-black */
html[data-theme="dark"]{
  color-scheme:dark;
  --bg:#171310;                     /* warm graphite — unlit tube glass */
  --side:#100D0B;                   /* recessed */
  --bubble:#241E17;                 /* elevated warm bubble */
  --ink:#F1E6D0;                    /* warm cream, 14.9:1 on --bg */
  --ink-2:rgba(241,230,208,.72);    /*  8.1:1 */
  --ink-3:rgba(241,230,208,.60);    /*  6.0:1 */
  --accent:#E8A445;                 /* warm amber glow, 8.6:1 */
  /* Darker + more saturated than the accent, at higher alpha. Landing the
     card 1.08:1 off the page (same separation light mode has) at the bright
     amber's own alpha would take α ≈ .07, at which the blue-turned-amber is
     imperceptible — the panel would read as merely "lighter" and lose its
     meaning. Chroma is nearly free on a dark surface; luminance is the
     scarce signal. So higher alpha carrying the accent's chroma. */
  --accent-bg:rgba(232,164,69,.13);
  --accent-2:#9CBC7E;               /* moss glow, secondary */
  --hair:rgba(241,220,180,.13);
  --hair-2:rgba(241,220,180,.075);
  --hover:rgba(241,220,180,.055);
  --hover-2:rgba(241,220,180,.09);
  --edge:rgba(241,220,180,.32);
  --send-fg:#171310;
  --img-ring:rgba(241,220,180,.11);
  --scrim:rgba(0,0,0,.96);
  --lift:0 0 40px rgba(0,0,0,.5);
}
*{box-sizing:border-box}
/* overflow-x:hidden is a belt-and-braces guard against long unbreakable tokens
   (URLs, dotted identifiers) inside an answer pushing the whole page sideways
   on a phone; overflow-wrap on .wrap below is the actual break, this is here
   so a corner case can never become a horizontal scroll. overscroll-behavior
   stops the pull-to-refresh / rubber-band that iOS otherwise treats as
   "the app is scrolling" and lets it fight the composer for the viewport. */
html,body{height:100%;margin:0;overflow-x:hidden;overscroll-behavior:none}
body{
  background-color:var(--bg);color:var(--ink);font-family:var(--sans);
  font-size:15px;line-height:1.6;-webkit-font-smoothing:antialiased;
  display:flex;overflow:hidden;
  /* Paper wash. Two very low-opacity radial gradients keep the page from
     reading as a flat colour block — the same trick a well-printed book uses
     with slight tonal variation across the sheet. Attached to body's own
     background, not a pseudo, so it can never layer over content. */
  background-image:
    radial-gradient(circle at 20% 30%, rgba(46,28,10,.03) 0, transparent 40%),
    radial-gradient(circle at 80% 70%, rgba(46,28,10,.025) 0, transparent 35%);
  background-attachment:fixed;
}
html[data-theme="dark"] body{
  background-image:
    radial-gradient(circle at 20% 30%, rgba(241,220,180,.022) 0, transparent 40%),
    radial-gradient(circle at 80% 70%, rgba(241,220,180,.018) 0, transparent 35%);
}
button{font-family:inherit;font-size:inherit;color:inherit;background:none;border:none;padding:0;cursor:pointer}

/* ---------------- sidebar ---------------- */
.side{
  /* min-width:0 is load-bearing: a flex item defaults to min-width:auto, so the
     longest nowrap chat title would otherwise inflate the basis past 268px and
     the ellipsis would never trigger. */
  flex:0 0 268px;min-width:0;
  background:var(--side);border-right:1px solid var(--hair-2);
  display:flex;flex-direction:column;padding:14px 10px;
}
.me{display:flex;align-items:center;gap:10px;padding:8px 10px 16px}
.me b{display:block;font-size:15px;font-weight:600;letter-spacing:-.01em}
.me span{display:block;font-size:13px;color:var(--ink-3);margin-top:1px}
/* Portrait next to the name. `object-position:center 22%` biases the crop
   upward — a straight center on a portrait usually cuts the face and puts
   the neckline in the middle of the circle. The 1px ring is the same token
   the lightbox uses, so it flips with the theme without extra rules. */
.avatar{
  width:40px;height:40px;border-radius:50%;flex:0 0 auto;
  object-fit:cover;object-position:center 22%;
  box-shadow:0 0 0 1px var(--img-ring);
}

.new{
  display:flex;align-items:center;gap:8px;width:100%;
  padding:8px 10px;border-radius:8px;font-size:14px;color:var(--accent);
  font-weight:500;margin-bottom:14px;transition:background .12s;
}
.new:hover{background:var(--hover)}
.new svg{flex:0 0 auto}

/* Sidebar section labels — machine-state signal, small mono uppercase with
   wide tracking. Reads as a filing tab rather than a heading. */
.side h2{
  font-family:var(--mono);
  font-size:11px;font-weight:500;color:var(--ink-3);letter-spacing:.10em;
  margin:0 0 4px;padding:0 10px;text-transform:uppercase;
}
/* Sidebar now hosts two groups — the seeded chats and the visitor's own asked
   questions. #groups is the single scrollable region; the individual lists
   inside scroll with it. Empty groups don't render, so the divider between
   them only exists when both do. */
.groups{flex:1 1 auto;overflow-y:auto;min-height:0}
.group + .group{margin-top:14px}
.sheets{list-style:none;margin:0;padding:0}
.sheets button{
  display:block;width:100%;text-align:left;padding:7px 10px;border-radius:8px;
  font-size:14px;color:var(--ink);white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis;transition:background .12s;
}
.sheets button:hover{background:var(--hover)}
.sheets button[aria-current="true"]{background:var(--hover-2);font-weight:500}

/* Sidebar footer: color-mode toggle on the left, socials on the right, one
   line. Everything in this row shares the same --ink-3 tone at rest so the
   theme label and the icons read as siblings rather than two separate
   footer regions. The socials are anchors out to email / linkedin / github,
   sourced from the reach category's frontmatter — the same file that feeds
   the CTA. Empty when no fields are set. */
.foot{
  display:flex;align-items:center;gap:6px;margin-top:10px;
  padding-top:8px;border-top:1px solid var(--hair-2);
}

.theme{
  display:flex;align-items:center;gap:8px;flex:0 1 auto;min-width:0;
  padding:7px 10px;border-radius:8px;font-size:13px;color:var(--ink-3);
  transition:background .12s,color .12s;
}
.theme:hover{background:var(--hover);color:var(--ink-2)}
.theme svg{flex:0 0 auto}

.socials{display:flex;gap:2px;margin-left:auto}
.socials a{
  display:grid;place-items:center;width:32px;height:32px;border-radius:8px;
  color:var(--ink-3);transition:background .12s,color .12s;
}
.socials a:hover{background:var(--hover);color:var(--ink)}
.socials a svg{display:block}

/* ---------------- main ---------------- */
.main{flex:1 1 auto;display:flex;flex-direction:column;min-width:0;position:relative}
/* Topbar is mobile-only now: on desktop the sidebar carries navigation and
   the topbar has nothing left to hold since the rotating fact line was
   removed. Kept in the markup and displayed at the mobile breakpoint to
   host the hamburger that opens the sidebar drawer. */
.topbar{display:none;flex:0 0 auto;height:52px;align-items:center;gap:10px;
  padding:0 22px;border-bottom:1px solid var(--hair-2);}
.menu{display:none;padding:6px;border-radius:6px}
.menu:hover{background:var(--hover)}

.thread{flex:1 1 auto;overflow-y:auto;padding:32px 22px 8px}
/* overflow-wrap:anywhere is the actual x-overflow fix — long identifiers and
   URLs inside answers wrap on any character rather than push the thread
   wider than the viewport. min-width:0 lets the flex parent honour the max
   rather than balloon to the widest child. */
.wrap{max-width:660px;margin:0 auto;min-width:0;overflow-wrap:anywhere}

/* Question bubble. Radius softened from 18px (pill) to 8px (paperback card),
   which is the geometry the rest of the surfaces use. Pill radii were the
   ChatGPT-shaped visual grammar the redesign was trying to leave. */
.q{display:flex;justify-content:flex-end;margin-bottom:26px}
.q span{
  background:var(--bubble);border-radius:8px;padding:9px 15px;
  max-width:82%;letter-spacing:-.005em;
}

/* Lede lifted from 19 to 20.5 — the current type scale had eight steps in a
   16px range and no step had any real weight. A bump on the lede opens a
   readable gap to body (15) and gives the first paragraph of an answer the
   emphasis it should already have had. */
.a{margin-bottom:14px}
.lede{font-size:20.5px;line-height:1.45;letter-spacing:-.015em;margin:0 0 22px;font-weight:400}
.lede b{font-weight:600}

.answer ul{margin:18px 0 0;padding-left:18px}
.answer li{margin-bottom:7px}
.answer li::marker{color:var(--ink-3)}

/* Focus card. Content, not chrome — an accent-tinted panel that hosts the
   label / head / where / bullets of a tailored answer. --accent-bg is the
   same low-alpha ember the code inline uses in both themes, so no new
   colour is introduced and the card follows the theme toggle automatically.
   Radius pulled from 14px (pill-ish) to 8px (paperback), matching the rest
   of the surfaces. The head is now Fraunces at moderate opsz + a touch of
   SOFT: the one place the display serif shows up in a body of text, so it
   has to earn the switch. */
.card{
  background:var(--accent-bg);
  border-radius:8px;
  padding:14px 16px;
  margin:18px 0;
}
.card-label{
  font-family:var(--mono);
  font-size:11px;font-weight:500;color:var(--accent);
  letter-spacing:.10em;text-transform:uppercase;margin:0 0 6px;
}
.card-head{
  font-family:var(--display);
  font-size:20px;font-weight:500;color:var(--ink);
  letter-spacing:-.01em;line-height:1.3;margin:0 0 4px;
  font-variation-settings:"opsz" 24,"SOFT" 30;
}
.card-where{font-size:13.5px;color:var(--ink-3);margin:0 0 10px}
.card ul{margin:6px 0 0;padding-left:18px}
.card li{margin-bottom:5px;color:var(--ink-2)}

/* Inline code. Was completely unstyled — browsers fell back to the OS default
   monospace at the same size as body, which read as broken text. Now uses
   the mono token at 90% and picks up the hover-2 wash as a chip-style bg. */
code{
  font-family:var(--mono);
  font-size:.9em;
  padding:1px 6px;
  border-radius:4px;
  background:var(--hover-2);
  color:var(--ink);
}

/* Followup. Quiet invitation with one primary affordance — the Yes button
   borrows --accent / --send-fg, the same pair the send button and the CTA
   primary use. Sits above the chips so the reader sees the single next
   step first, and the chips remain as the broader browse path. Radius
   pulled in to match the card's 8px so the surface language is consistent. */
.followup{
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  margin:20px 0 4px;color:var(--ink-2);font-size:14px;
}
.followup button{
  padding:6px 14px;border-radius:8px;font-size:13.5px;font-weight:500;
  color:var(--send-fg);background:var(--accent);transition:opacity .12s;
}
.followup button:hover{opacity:.9}

/* lightbox */
.box{position:fixed;inset:0;z-index:50;background:var(--scrim);display:none;place-items:center;padding:6vh 6vw}
.box.on{display:grid}
.box img{max-width:100%;max-height:84vh;border-radius:4px;display:block}
.box .cap{
  position:absolute;left:0;right:0;bottom:26px;text-align:center;
  color:rgba(255,255,255,.6);font-size:12.5px;padding:0 40px;
}
.box .x{
  position:absolute;top:18px;right:20px;width:34px;height:34px;border-radius:50%;
  color:rgba(255,255,255,.75);display:grid;place-items:center;
}
.box .x:hover{background:rgba(255,255,255,.12)}

/* Chips — the biggest structural change. Were ChatGPT-shaped outlined pills
   (16px radius, 1px hair border), which was the last thing making the UI
   read as a generic chat clone. Now: plain sans text with a hairline
   underline that lifts to the accent on hover — reads as a footnote link,
   not a UI control. */
.fups{display:flex;flex-wrap:wrap;gap:10px 22px;margin-top:22px}
.fups button{
  border:none;background:transparent;padding:0;
  font:inherit;font-weight:400;
  font-size:15px;line-height:1.4;
  color:var(--ink-2);
  text-decoration:underline;
  text-decoration-thickness:1px;
  text-decoration-color:var(--hair);
  text-underline-offset:4px;
  transition:color .12s,text-decoration-color .12s;
}
.fups button:hover{color:var(--accent);text-decoration-color:var(--accent)}

.miss p{margin:0 0 14px}

/* The two de-emphasis tones the rendered answers reach for: secondary body copy
   (a miss body, an error message) and the pending placeholder. These were inline
   style attributes on the elements themselves until the CSP went strict —
   style-src 'self' does not cover a style="" attribute, and two classes are a
   smaller price than 'unsafe-inline'. */
.dim{color:var(--ink-2)}
.dimmer{color:var(--ink-3)}

/* The out-of-tokens CTA. Framed as an empty state with direction rather than
   an error: the copy stays in the miss body, and this block sits underneath
   the chips (still present) so it never dead-ends the visitor.
   Primary action uses --accent with --send-fg — a token pair the send button
   already relies on — which holds ≥ 5.6:1 in both themes without introducing
   a new colour. Secondary is a tinted link matching the "Ask something" nav
   button. */
.cta{display:flex;flex-wrap:wrap;gap:8px;margin-top:22px}
.cta a{
  display:inline-flex;align-items:center;gap:8px;
  padding:10px 18px;border-radius:22px;
  font-size:15px;font-weight:500;letter-spacing:-.005em;
  text-decoration:none;transition:opacity .12s,background .12s;
}
.cta a svg{flex:0 0 auto}
.cta-primary{background:var(--accent);color:var(--send-fg)}
.cta-primary:hover{opacity:.9}
.cta-secondary{color:var(--accent)}
.cta-secondary:hover{background:var(--accent-bg)}

/* Visible keyboard focus. `outline` follows border-radius on every browser
   we support, so one rule covers chips, rounded list items and the
   composer alike. `:focus` alone (mouse focus on non-inputs) stays quiet. */
:focus{outline:none}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

/* Blinking block cursor for the pending state. Sits at the end of the
   "Thinking..." line and reads as a running process rather than a
   loading spinner — one of the only places the app has genuine motion,
   and one of the cheapest ways to add character. Two-frame animation via
   steps() so it snaps rather than fades: a real terminal cursor blink,
   not a CSS transition. */
.cursor{
  display:inline-block;margin-left:3px;
  color:var(--accent);
  font-family:var(--mono);
  animation:cursor-blink 1s steps(2,jump-none) infinite;
}
@keyframes cursor-blink{50%{opacity:0}}

/* Power-on. First paint of the whole app fades from ~40% opacity to full
   over 340ms with a tiny lift — the tube warming up, in one keyframes. The
   whole app used to have zero @keyframes (only one WAAPI animation on the
   composer FLIP), so this is deliberately restrained. Gated behind
   reduced-motion, and `animation-fill-mode: both` pins the final state
   so a slow paint doesn't flash the intermediate frame. */
@keyframes power-on{
  from{opacity:.4;transform:translateY(4px)}
  to  {opacity:1; transform:translateY(0)}
}
body{animation:power-on 340ms cubic-bezier(.22,1,.36,1) both}
/* prefers-reduced-motion is honoured by the blanket rule at the bottom of
   this file, which kills both transitions and animations. */

/* ---------------- composer ----------------
   Composer pulled off ChatGPT's 22px pill onto a 10px paperback rectangle.
   Still identifies as an input on hover/focus (border + focus-within edge),
   but the geometry no longer echoes the chat clone it started as.
   The send button becomes the one glowing amber element on the composer —
   used to be filled with --ink (a small black dot); now filled with --accent
   (burnt sienna in light, amber in dark), which reads as the power lamp on
   the row and makes the primary action visually primary. */
.composer{flex:0 0 auto;padding:12px 22px 22px}
.composer form{
  max-width:660px;margin:0 auto;display:flex;align-items:center;gap:8px;
  border:1px solid var(--hair);border-radius:10px;padding:7px 7px 7px 17px;
  background:var(--bg);transition:border-color .15s;
}
.composer form:focus-within{border-color:var(--edge)}
.composer input{
  flex:1 1 auto;border:none;outline:none;font-family:inherit;font-size:15px;
  color:var(--ink);background:none;padding:5px 0;letter-spacing:-.005em;
}
.composer input::placeholder{color:var(--ink-3)}
.send{
  flex:0 0 auto;width:30px;height:30px;border-radius:50%;
  background:var(--accent);color:var(--send-fg);
  display:grid;place-items:center;transition:opacity .15s;
}
.send:disabled{opacity:.28;cursor:default}
/* Warm bloom on the amber send button in dark mode only — a soft halo, not
   a hard glow. Deliberately absent in light mode where the accent is a
   deep ember and a bloom would look sooty rather than lit. */
html[data-theme="dark"] .send:not(:disabled){
  box-shadow:0 0 12px rgba(232,164,69,.35),0 0 3px rgba(232,164,69,.5);
}

/* ---------------- landing ----------------
   The centered hero state that greets a new visitor. `body.landing` swaps
   which flex child grows: the thread collapses and the composer takes the
   column, so its own justify-content:center parks the greeting/form/chips
   in the middle. `.hero` and `.starters` fade rather than display:none,
   because setLanding() FLIPs the form on class-toggle and a hard collapse
   would flash before the animation started. */
/* Hero — the one place the display serif gets to be genuinely large. Landing
   headline lifts from 28px sans (a big-ish body size) to 44px Fraunces with
   a high SOFT axis value, which is the wonky, warm cut of the family that
   makes the greeting feel written rather than emitted. This is the largest
   type step in the whole app and it should feel obviously larger than
   anything else. */
.hero{text-align:center;width:100%;max-width:660px;margin:0 auto 22px}
.hero h1{
  font-family:var(--display);
  font-size:44px;font-weight:500;letter-spacing:-.02em;
  line-height:1.1;
  font-variation-settings:"opsz" 84,"SOFT" 30;
  margin:0 0 8px;color:var(--ink);
}
.hero p{margin:0;color:var(--ink-3);font-size:15px;letter-spacing:-.005em}
/* Starters follow chips — same text-link treatment. Slightly more generous
   gaps because they sit under the landing composer with air on both sides. */
.starters{
  display:flex;flex-wrap:wrap;gap:12px 24px;justify-content:center;
  width:100%;max-width:660px;margin:20px auto 0;
}
.starters button{
  border:none;background:transparent;padding:0;
  font:inherit;font-weight:400;
  font-size:15px;line-height:1.4;
  color:var(--ink-2);
  text-decoration:underline;
  text-decoration-thickness:1px;
  text-decoration-color:var(--hair);
  text-underline-offset:4px;
  transition:color .12s,text-decoration-color .12s;
}
.starters button:hover{color:var(--accent);text-decoration-color:var(--accent)}

.hero,.starters{transition:opacity .14s ease}
body:not(.landing) .hero,
body:not(.landing) .starters{position:absolute;opacity:0;pointer-events:none}

body.landing .thread{flex:0 0 auto;padding:0}
body.landing .composer{
  flex:1 1 auto;display:flex;flex-direction:column;
  justify-content:center;align-items:center;padding:22px;
}
body.landing .composer form{width:100%}

@media (max-width:820px){
  /* The drawer needs an explicit width now that it's out of the flex flow:
     flex-basis doesn't apply to position:absolute, so without this the panel
     shrinks to its widest child (usually the longest chat title) and misses
     the "cover the left side of the screen" affordance on very narrow
     viewports. min() caps it below 320px so the tiniest phones still see
     part of the main behind the drawer. */
  .side{
    position:absolute;z-index:10;top:0;bottom:0;left:0;
    width:min(280px,85vw);
    transform:translateX(-100%);transition:transform .22s ease;
    box-shadow:var(--lift);
  }
  body.nav .side{transform:none}
  .topbar{display:flex}
  .menu{display:grid;place-items:center}
  .thread{padding-top:24px}
  /* iOS auto-zooms text inputs whose font-size is below 16px, which is the
     real "the page moves around when I tap" that a mobile visitor sees. Only
     bumped on narrow viewports so desktop density stays the intended 15px. */
  .composer input{font-size:16px}
  /* HIG asks for at least 44pt touch targets. Desktop density is unchanged;
     these only bump on narrow viewports, where every tap is a finger. */
  .sheets button{min-height:44px;padding-top:10px;padding-bottom:10px}
  .fups button{min-height:44px;padding-top:10px;padding-bottom:10px}
  .followup button{min-height:44px;padding-top:10px;padding-bottom:10px}
  .starters button{min-height:44px;padding-top:10px;padding-bottom:10px}
  .socials a{width:44px;height:44px}
  .cta a{min-height:44px}
  .hero h1{font-size:34px;line-height:1.08}
  .hero p{font-size:14px}
}
@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}
