/* Two palettes, one set of token names. Everything below this block paints with
   var(--x) only, so a theme is a token block and nothing else. Light is the
   default on bare :root; dark is applied twice with the same values -- once for
   the OS preference (only while nothing is forced) and once for the forced
   choice, so the drawer's Auto/Light/Dark control wins in both directions.
   The *-rgb triplets exist because rgba() cannot take a hex token: every
   translucent tint and shadow reads them. */
:root{
  --paper:#f3ead9; --paper-2:#f8f1e3; --card:#fbf6ec;
  --ink:#3b3325; --ink-soft:#6f6350; --muted:#9a8b73;
  --ember:#c05a34; --ember-soft:#d98a5a; --glow:#e9b878;
  --ember-deep:#a94e2c; --on-ember:#fff; --danger:#b83232;
  --line:#e6d8bf; --line-2:#efe4ce;
  --paper-rgb:243,234,217; --glow-rgb:233,184,120; --muted-rgb:154,139,115;
  --ember-rgb:192,90,52; --ember-soft-rgb:216,138,90;
  /* shadows and scrims: ink-coloured in light, plain black in dark -- a cream
     shadow on charcoal reads as a glow */
  --shade-rgb:59,51,37;
  --shadow:0 1px 2px rgba(var(--shade-rgb),.05),0 8px 30px rgba(var(--shade-rgb),.07);
  /* the lightbox is a dark surround in BOTH themes (a photo viewer wants one),
     so its tokens are defined once here and never redefined below. --lb-ink is
     light text on that dark surface: it must not follow --paper-2. */
  --lb-backdrop:rgba(38,28,16,.74); --lb-surface:rgba(38,28,16,.5);
  --lb-edge:rgba(233,184,120,.3); --lb-ring:rgba(233,184,120,.22); --lb-ink:#f8f1e3;
  /* --danger flips with the theme; this surface never does, so it needs its own */
  --lb-danger:#e2705c;
  /* one reading column, one gutter. The thread lives inside .wrap's padding,
     so anything meant to line up with the bubbles (composer, quote bar) has to
     be the column MINUS that gutter, not the column itself. */
  --col:720px; --gutter:22px;
}
/* dark: the same nook after the lamps go out. Warm charcoal rather than grey so
   the ember and the cream text still belong to the same room; ember a step
   brighter because the original sinks into a dark ground. */
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    --paper:#1c1712; --paper-2:#221c16; --card:#2b231b;
    --ink:#efe4d0; --ink-soft:#c4b59c; --muted:#8f8069;
    --ember:#d0663e; --ember-soft:#e0946a; --glow:#e9b878;
    --ember-deep:#b8562f; --on-ember:#fff; --danger:#e26b6b;
    --line:#372d22; --line-2:#2f261d;
    --paper-rgb:28,23,18; --muted-rgb:143,128,105;
    --ember-rgb:208,102,62; --ember-soft-rgb:224,148,106;
    --shade-rgb:0,0,0;
    --shadow:0 1px 2px rgba(0,0,0,.3),0 8px 30px rgba(0,0,0,.35);
  }
}
:root[data-theme="dark"]{
  --paper:#1c1712; --paper-2:#221c16; --card:#2b231b;
  --ink:#efe4d0; --ink-soft:#c4b59c; --muted:#8f8069;
  --ember:#d0663e; --ember-soft:#e0946a; --glow:#e9b878;
  --ember-deep:#b8562f; --on-ember:#fff; --danger:#e26b6b;
  --line:#372d22; --line-2:#2f261d;
  --paper-rgb:28,23,18; --muted-rgb:143,128,105;
  --ember-rgb:208,102,62; --ember-soft-rgb:224,148,106;
  --shade-rgb:0,0,0;
  --shadow:0 1px 2px rgba(0,0,0,.3),0 8px 30px rgba(0,0,0,.35);
}
*{box-sizing:border-box}
/* Keyboard focus, everywhere, in one place.
   There were no focus styles at all -- every control fell back to the browser's
   default ring, which is drawn in currentColor and so came out cream-on-cream in
   one theme and near-invisible in the other, and which an ancestor's
   overflow:hidden silently clips (.drawer-card and .pc-modal both do).
   :focus-visible, not :focus, so a mouse click does not leave a ring behind;
   ember because it is the one colour that reads on both palettes; and a second
   ring in the page colour underneath, so it stays legible against an ember
   button too. The offset is what keeps it outside a clipping parent's edge. */
:focus-visible{outline:2px solid var(--ember-soft);outline-offset:2px;
  box-shadow:0 0 0 4px var(--paper);border-radius:inherit}
/* on the dark overlay the page colour is the wrong second ring */
.lightbox :focus-visible,.pc-modal :focus-visible{box-shadow:0 0 0 4px var(--lb-backdrop)}
/* the composer pill already draws its own ring via :focus-within, so the
   textarea inside it must not draw a second one on top */
#composer:focus-visible{outline:none;box-shadow:none}
/* the message text, and only it, preserves the model's line breaks. Keeping this
   off the bubble means a stray newline between the bubble's children collapses
   instead of drawing a blank line above a photo. */
.msg-text{white-space:pre-wrap;overflow-wrap:break-word}
/* While something is generating, the controls that would interfere with it are
   out of reach -- a picture takes 10-15 seconds and every race we have had came
   from pressing something inside that window. Deliberately NOT everything:
   scrolling, the drawer, the back arrow, closing the lightbox and paging its
   gallery all stay live, because none of them can corrupt what is in flight and
   locking a whole screen for fifteen seconds feels broken rather than careful. */
body.ui-busy .tact,
body.ui-busy .mitem,
body.ui-busy .swarr,
body.ui-busy .lb-default,
body.ui-busy .lb-del,
body.ui-busy .lb-draw,
body.ui-busy .lb-change,
body.ui-busy .imagine,
body.ui-busy .cmd,
body.ui-busy .slash{pointer-events:none;opacity:.4;transition:opacity .15s}
/* a generation that came back with nothing. Quiet on purpose: it is a hiccup
   worth explaining, not an error worth alarming about, and the retry beside it
   almost always works. */
.genfail{display:flex;align-items:center;gap:10px;margin:2px 0 0;
  font-family:'EB Garamond',serif;font-style:italic;font-size:13px;color:var(--muted)}
.genfail-again{font-family:'Fraunces',serif;font-style:normal;font-size:13px;
  color:var(--ember);background:none;border:none;padding:2px 0;cursor:pointer;
  border-bottom:1px solid var(--ember-soft);line-height:1.2;
  -webkit-tap-highlight-color:transparent}
.genfail-again:hover{color:var(--ember-deep);border-color:var(--ember-deep)}
/* "typing": three dots in the bubble while the reply is being written, instead
   of the reply assembling itself a word at a time. A text message arrives whole,
   so this is what the app is imitating. The dots rise in sequence rather than
   fade together -- a fade reads as loading, a bounce reads as someone there. */
.typing{display:inline-flex;align-items:center;gap:5px;padding:3px 2px}
.tdot{width:7px;height:7px;border-radius:50%;background:var(--ink-soft);opacity:.45;
  animation:tdot 1.25s ease-in-out infinite}
.tdot:nth-child(2){animation-delay:.16s}
.tdot:nth-child(3){animation-delay:.32s}
@keyframes tdot{
  0%,60%,100%{transform:translateY(0);opacity:.35}
  30%{transform:translateY(-4px);opacity:.9}
}
@media (prefers-reduced-motion:reduce){
  .tdot{animation:none;opacity:.55}
}
/* Inline SVG icons (icons.py). They size from the element that holds them rather
   than from font-size, so every button that used to hold a glyph sets one here.
   currentColor means a single icon serves the cream bubble and the ember one. */
.ico{width:1em;height:1em;flex:none;display:block;stroke-width:2}
button .ico,a .ico{pointer-events:none}   /* clicks belong to the control, not the path */
[hidden]{display:none!important}  /* author display rules otherwise beat the UA [hidden] */
/* color-scheme tells the browser which of ITS OWN colours to use for this page:
   form controls, scrollbars, and the context menu of an installed app window
   (Edge painted a light menu over the dark OS because this said "light"). */
html{-webkit-text-size-adjust:100%;color-scheme:light dark}
html[data-theme="light"]{color-scheme:light}
html[data-theme="dark"]{color-scheme:dark}
body{
  margin:0; background:var(--paper); color:var(--ink);
  font-family:'EB Garamond',Georgia,serif; font-size:19px; line-height:1.7;
  background-image:
    radial-gradient(1200px 600px at 80% -10%, rgba(var(--glow-rgb),.14), transparent 60%),
    radial-gradient(900px 500px at -10% 110%, rgba(var(--ember-rgb),.08), transparent 55%);
  background-attachment:fixed;
}
a{color:inherit;text-decoration:none}
.wrap{max-width:var(--col);margin:0 auto;padding:0 var(--gutter)}

/* header */
header{position:sticky;top:0;z-index:5;backdrop-filter:blur(8px);
  background:linear-gradient(var(--paper),rgba(var(--paper-rgb),.75));
  border-bottom:1px solid var(--line)}
.bar{display:flex;align-items:center;gap:14px;height:64px}
.brand{font-family:'Fraunces',serif;font-weight:600;font-size:23px;letter-spacing:.2px;
  display:flex;align-items:center;gap:9px}
.brand .flame{filter:drop-shadow(0 0 6px var(--glow))}
.spacer{flex:1}
.ghost{font-family:'Fraunces',serif;font-size:15px;color:var(--ink-soft);
  padding:8px 14px;border:1px solid var(--line);border-radius:999px;background:var(--card);
  transition:.2s}
.ghost:hover{border-color:var(--ember-soft);color:var(--ember)}

/* landing. Four (soon five) identical full-width forms stacked to ~2.6 phone
   screens, which made starting anything a scroll and buried the sessions she
   actually comes back to. The cards are compact now and pair up on a wide
   screen, so adding a mode costs a row rather than a screen. */
.hero{position:relative;padding:44px 0 16px;text-align:center}
/* the fire the copy keeps promising, finally on the page: a slow ember breath
   behind the title. The one moving thing here, so it stays slow and dim. */
.hero::before{content:"";position:absolute;left:50%;top:6px;width:min(460px,92vw);height:190px;
  transform:translateX(-50%);pointer-events:none;
  background:radial-gradient(closest-side,rgba(var(--glow-rgb),.34),transparent 72%);
  animation:breathe 7.5s ease-in-out infinite}
@keyframes breathe{
  0%,100%{opacity:.5;transform:translateX(-50%) scale(1)}
  50%{opacity:1;transform:translateX(-50%) scale(1.07)}}
.hero h1{position:relative;font-family:'Fraunces',serif;font-weight:400;font-size:44px;
  line-height:1.1;margin:0 0 10px}
.hero p{position:relative;color:var(--ink-soft);font-style:italic;margin:0;font-size:20px}

/* the launcher: one button per mode, four in a grid. Adding a mode costs a cell,
   not a screen, and the page below the fold stays hers. */
.modegrid{display:grid;grid-template-columns:1fr 1fr;gap:12px;padding:14px 0 34px}
/* one card (person is the only mode offered) sits centred at half width, not in the left column */
.modegrid:has(.modebtn:only-child){grid-template-columns:minmax(0,1fr);justify-content:center;max-width:50%;margin:0 auto}
.modebtn{display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:9px;min-height:118px;padding:18px 12px;text-align:center;
  background:var(--card);border:1px solid var(--line);border-radius:17px;
  box-shadow:var(--shadow);transition:.2s;position:relative;overflow:hidden;
  -webkit-tap-highlight-color:transparent;animation:rise .5s ease both}
.modebtn:nth-child(2){animation-delay:.05s}
.modebtn:nth-child(3){animation-delay:.1s}
.modebtn:nth-child(4){animation-delay:.15s}
.modebtn:nth-child(n+5){animation-delay:.2s}
.modebtn::after{content:"";position:absolute;inset:0;opacity:0;transition:.2s;
  background:radial-gradient(200px 90px at 50% 0,rgba(var(--glow-rgb),.26),transparent 72%)}
.modebtn:hover{transform:translateY(-2px);border-color:var(--ember-soft)}
.modebtn:hover::after{opacity:1}
.mb-i{font-size:30px;line-height:1;position:relative;z-index:1;
  filter:drop-shadow(0 3px 8px rgba(var(--ember-rgb),.18));transition:.2s}
.modebtn:hover .mb-i{transform:scale(1.08)}
.mb-l{font-family:'Fraunces',serif;font-weight:500;font-size:19px;color:var(--ink);
  position:relative;z-index:1}

/* the mode's own page: one thing to read, one thing to fill in */
.start{padding-block:16px 60px}
.start .backbtn{margin-bottom:8px}
.startcard{max-width:460px;margin:6vh auto 0;text-align:center;position:relative}
.startcard::before{content:"";position:absolute;left:50%;top:-26px;width:340px;height:170px;
  transform:translateX(-50%);pointer-events:none;
  background:radial-gradient(closest-side,rgba(var(--glow-rgb),.34),transparent 72%);
  animation:breathe 7.5s ease-in-out infinite}
.start-icon{position:relative;display:block;font-size:52px;line-height:1;margin:0 0 12px;
  filter:drop-shadow(0 4px 14px rgba(var(--ember-rgb),.22))}
.start-title{position:relative;font-family:'Fraunces',serif;font-weight:400;font-size:38px;
  line-height:1.1;margin:0 0 10px}
.start-blurb{position:relative;color:var(--ink-soft);font-size:19px;line-height:1.5;
  margin:0 auto 26px;max-width:24em}
.start-form{position:relative;display:flex;gap:9px}
.start-input{flex:1;min-width:0;font-family:'EB Garamond',serif;font-size:18px;color:var(--ink);
  background:var(--card);border:1px solid var(--line);border-radius:13px;
  padding:13px 15px;outline:none;box-shadow:var(--shadow);transition:.15s}
.start-input::placeholder{color:var(--muted);font-style:italic}
.start-input:focus{border-color:var(--ember-soft);box-shadow:0 0 0 3px rgba(var(--ember-soft-rgb),.15),var(--shadow)}
.begin{flex:none;font-family:'Fraunces',serif;font-size:14px;color:var(--on-ember);background:var(--ember);
  border:none;border-radius:11px;padding:0 17px;cursor:pointer;transition:.2s;
  white-space:nowrap;-webkit-tap-highlight-color:transparent}
.start-begin{font-size:15px;border-radius:13px;padding:0 20px}
.begin:hover{background:var(--ember-deep)}
/* Begin while the persona card is being written: still ember, visibly busy, and
   unclickable so a second press cannot open a second session */
.begin.working{background:var(--ember-soft);pointer-events:none;
  animation:pulse 1.1s ease-in-out infinite}

/* recent. These are the fires already lit, so the rows carry more weight than
   the mode cards' inputs do -- this is what she opens the app to reach. */
.recent{padding:0 0 58px}
.recent .cap{display:flex;align-items:center;gap:12px;margin:0 0 6px;
  font-family:'Fraunces',serif;color:var(--muted);font-size:13px;
  text-transform:uppercase;letter-spacing:.14em}
.recent .cap::after{content:"";flex:1;height:1px;background:var(--line)}
.slist{display:flex;flex-direction:column}
.srow{display:flex;align-items:baseline;gap:12px;padding:14px 10px;
  border-top:1px solid var(--line-2);transition:.16s}
.srow:first-child{border-top:none}
.srow:hover{background:var(--card)}
.srow .m{font-size:14px;flex:none}
.srow .t{flex:1;min-width:0;font-family:'Fraunces',serif;font-size:17px;color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.srow .d{flex:none;color:var(--muted);font-size:13px;font-style:italic}
.srow .c{flex:none;color:var(--muted);font-size:13px;font-variant-numeric:tabular-nums}
/* a row is a link; say so without needing markup for it */
.srow::after{content:"›";flex:none;color:var(--line);font-size:17px;line-height:1;
  transition:.16s}
.srow:hover::after{color:var(--ember);transform:translateX(2px)}

/* reading view */
.read{padding-block:18px 160px}   /* padding-block, not the shorthand: the sides
                                     belong to .wrap, and a shorthand here zeroed
                                     them, so bubbles sat flush to the screen edge
                                     on any width narrow enough to not center */
.tag{font-family:'Fraunces',serif;font-size:12px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ember);margin:0 0 26px;display:flex;align-items:center;gap:8px}
.thread>*{animation:rise .5s ease both}
/* the sentinel that pulls the previous page: a hair tall so an intersection
   observer has something to see; the id outranks .thread.person>* for the animation */
#thread>.older{height:1px;animation:none}
@keyframes rise{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.prose{font-size:20px;line-height:1.78;overflow-wrap:break-word;margin:0 0 24px;color:var(--ink)}
.prose em{color:var(--ember-soft);font-style:italic}
.steer{margin:26px 0 22px;padding-left:16px;border-left:2px solid var(--ember-soft);
  color:var(--ink-soft);font-style:italic;font-size:17px}
.steer .who{font-family:'Fraunces',serif;font-style:normal;font-size:11px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--muted);display:block;margin-bottom:2px}
.cursor::after{content:"▍";color:var(--ember);animation:blink 1s steps(2) infinite;margin-left:1px}
@keyframes blink{0%,50%{opacity:1}50.01%,100%{opacity:0}}

/* composer */
.compose{position:fixed;left:0;right:0;bottom:0;z-index:6;
  background:linear-gradient(rgba(var(--paper-rgb),0),var(--paper) 34%);
  padding:26px var(--gutter) 22px;
  /* the transparent gradient top overlapped the last bubble's tool buttons and
     ate their hover/clicks; make the bar click-through and re-arm its own controls */
  pointer-events:none}
.compose > *{pointer-events:auto}
/* One pill. The field and its buttons used to be three separate boxes in a row,
   which on a phone spent ~40% of the width on a text "Send" and a bordered
   polish square. Now the pill carries the border and the focus ring, the
   textarea inside is transparent, and the buttons sit in it. */
.cinner{max-width:calc(var(--col) - var(--gutter)*2);margin:0 auto;
  display:flex;gap:6px;align-items:flex-end;
  background:var(--card);border:1px solid var(--line);border-radius:24px;
  padding:5px 5px 5px 6px;box-shadow:var(--shadow);transition:.15s}
.cinner:focus-within{border-color:var(--ember-soft);box-shadow:0 0 0 3px rgba(var(--ember-soft-rgb),.15),var(--shadow)}
/* scoped to the composer: the bare `textarea` rule below also dresses .editbox,
   and the message editor is not in a pill */
#composer{flex:1;min-width:0;align-self:center;
  background:none;border:none;box-shadow:none;border-radius:0;
  padding:11px 4px 11px 10px;max-height:160px}
#composer:focus{border:none;box-shadow:none}
textarea{flex:1;font-family:'EB Garamond',serif;font-size:18px;line-height:1.5;color:var(--ink);
  background:var(--card);border:1px solid var(--line);border-radius:16px;padding:14px 16px;resize:none;
  outline:none;box-shadow:var(--shadow);max-height:180px}
textarea:focus{border-color:var(--ember-soft);box-shadow:0 0 0 3px rgba(var(--ember-soft-rgb),.15),var(--shadow)}
/* the buttons stay on the bottom edge so a grown textarea pushes the pill up
   around them rather than dragging them to the middle */
.cbtns{flex:none;display:flex;align-items:center;gap:4px;padding-bottom:1px}
/* 42px keeps a 44px-ish tap target without making the pill tall */
.send{display:flex;align-items:center;justify-content:center;
  width:42px;height:42px;border-radius:50%;color:var(--on-ember);background:var(--ember);border:none;
  cursor:pointer;transition:.2s;-webkit-tap-highlight-color:transparent}
.send:hover{background:var(--ember-deep)}
.send:disabled{opacity:.45;cursor:default}
/* Send becomes Stop while a reply is coming: same button, so the thumb does
   not have to move, and the icon says which one it is now */
.send .send-stop{display:none}
.send.stopping > .ico{display:none}
.send.stopping .send-stop{display:flex}
.send.stopping{background:var(--card);color:var(--ember);box-shadow:inset 0 0 0 1px var(--line)}
/* ✨ rewrite-my-draft: a ghost beside the send arrow, not a bordered box */
/* square, or border-radius:50% draws an ellipse. 42 to match .send beside it --
   these two sit in the same pill and any difference reads as a mistake. */
.polish{display:flex;align-items:center;justify-content:center;
  width:42px;height:42px;border-radius:50%;background:none;border:none;
  cursor:pointer;transition:.2s;color:var(--muted);-webkit-tap-highlight-color:transparent}
.polish:hover{color:var(--ember)}
.polish:disabled{opacity:.6;cursor:default}
.polish.spin{animation:spin .8s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}
.hint{max-width:calc(var(--col) - var(--gutter)*2);margin:8px auto 0;text-align:center;color:var(--muted);font-size:13px;font-style:italic}
/* context-window gauge under the composer: how full the 1M window is, plus a
   manual Summarize button that only appears once it's nearly full */
.usage{max-width:calc(var(--col) - var(--gutter)*2);margin:5px auto 0;
  display:flex;align-items:center;justify-content:center;gap:10px;
  color:var(--muted);font-family:'Fraunces',serif;font-size:12px}
.usage-sum{font-family:'Fraunces',serif;font-size:12px;color:var(--ember);
  background:var(--card);border:1px solid var(--ember-soft);border-radius:10px;
  padding:3px 11px;cursor:pointer;transition:.2s}
.usage-sum:hover{background:var(--ember);color:var(--on-ember)}
/* "/" in the pill: same ghost as polish, but a glyph rather than an icon */
/* the glyph is narrower than the sparkle, but the BOX must stay square: a width
   override here was what made the focus ring around it visibly oval */
.slash{font-family:'Fraunces',serif;font-size:21px;font-weight:500;line-height:1}
/* the command popover, in flow above the pill so opening it lifts the pill
   (and the keyboard anchor's height measurement follows). One row per command. */
.cmdpop{max-width:calc(var(--col) - var(--gutter)*2);margin:0 auto 8px;
  background:var(--card);border:1px solid var(--line);border-radius:16px;
  box-shadow:var(--shadow);padding:5px;display:flex;flex-direction:column;gap:2px}
.cmd{display:flex;align-items:baseline;gap:12px;width:100%;text-align:left;
  background:none;border:none;border-radius:11px;padding:9px 12px;cursor:pointer;
  transition:.15s;-webkit-tap-highlight-color:transparent}
.cmd:hover{background:var(--paper-2)}
.cmd-name{flex:none;font-family:'Fraunces',serif;font-size:15px;font-weight:500;color:var(--ember)}
.cmd-desc{font-size:15px;color:var(--ink-soft);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* person mode: texting bubbles, not fiction prose. Each message is a .msgwrap
   column (bubble + reaction chip + tools), aligned left (them) or right (me). */
.thread.person{display:flex;flex-direction:column;gap:11px}
.thread.person>*{animation:rise .35s ease both}
.msgwrap{display:flex;flex-direction:column;max-width:82%}
.msgwrap.them{align-self:flex-start;align-items:flex-start}
.msgwrap.me{align-self:flex-end;align-items:flex-end}
.thread.person .prose{max-width:100%;background:var(--card);
  border:1px solid var(--line);border-radius:19px 19px 19px 6px;padding:9px 14px;margin:0;
  font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;font-size:16px;line-height:1.45;
  color:var(--ink)}
.thread.person .steer{max-width:100%;background:var(--ember);color:var(--on-ember);
  border:none;border-left:none;border-radius:19px 19px 6px 19px;padding:9px 14px;margin:0;
  font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;font-style:normal;font-size:16px}
.thread.person .steer .who{display:none}
/* narration (*action*) reads quieter than speech, on each bubble side */
.thread.person .prose em{color:var(--muted);font-style:italic}
.thread.person .steer em{color:rgba(255,255,255,.72);font-style:italic}

/* SYSTEM: steering note -- a dimmed centered aside, not a chat bubble */
.sysrow{max-width:520px;margin:5px auto;display:flex;flex-direction:column;align-items:center}
.sysnote{background:rgba(var(--muted-rgb),.1);border:1px dashed var(--line);border-radius:12px;
  padding:7px 15px;color:var(--muted);font-size:14px;font-style:italic;text-align:center;
  font-family:'EB Garamond',serif;line-height:1.4}
.syslbl{font-family:'Fraunces',serif;font-style:normal;font-size:10px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ember-soft);margin-right:8px;vertical-align:1px}
.systools{display:flex;gap:5px;margin-top:3px;opacity:.35;transition:.15s}
.sysrow:hover .systools{opacity:1}
@media (hover:none){.systools{opacity:.5}}
.systool{background:none;border:none;cursor:pointer;font-size:13px;color:var(--muted);
  padding:2px 6px;border-radius:6px}
.systool:hover{color:var(--ember)}

/* the message's row id, admin only. Hidden unless the thread carries .showids,
   which is set once on the container: an htmx-swapped bubble cannot know who is
   viewing, so visibility is inherited rather than re-decided per fragment. */
.msgid{display:none}
.showids .msgid{display:inline-block;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:11px;color:var(--muted);opacity:.7;letter-spacing:.02em;
  padding:2px 5px;border-radius:6px;background:var(--card);
  user-select:all;cursor:text;align-self:center}
.showids .msgid:hover{opacity:1;color:var(--ember)}

/* A sent photo inside a bubble. The photo fills the bubble rather than sitting
   at a fixed 260px inside it: a long caption used to stretch the bubble to 554px
   on a desktop and leave 266px of empty cream beside the picture. Capping the
   bubble to the photo instead would have wrapped the caption into a ~30-character
   column, so the photo grows to meet the caption. Sources are 1408px wide, so
   showing them larger costs nothing. */
.msg-img{display:block;width:100%;max-width:360px;border-radius:14px;margin:0 0 3px;
  border:1px solid var(--line);cursor:zoom-in}
.thread.person .prose:has(.msg-img),
.thread.person .steer:has(.msg-img){max-width:min(100%,390px)}
/* the photo bleeds to the bubble's edges -- it was sitting inside 9px/14px of
   padding, which framed it in dead cream on all four sides. The bubble needs a
   definite width for that: bleeding by percentage against a bubble that had
   shrunk to fit a short caption made the photo shrink with it. */
/* the definite width has to start at the wrapper: a percentage on the bubble
   resolves against a parent that is itself sizing to the bubble, which is
   circular and collapses back to the caption's width */
.thread.person .msgwrap:has(.msg-img){width:min(100%,390px)}
.thread.person .prose:has(> .msg-img:first-child),
.thread.person .steer:has(> .msg-img:first-child){width:100%}
.thread.person .prose > .msg-img:first-child,
.thread.person .steer > .msg-img:first-child{
  width:calc(100% + 28px);max-width:none;margin:-9px -14px 8px;
  border:none;border-radius:17px 17px 2px 2px}
.thread.person .steer .msg-img{margin-bottom:6px}
/* a voice note. The <audio> is hidden and app.js drives these three parts, so the
   player is the app's rather than whichever grey slab the browser ships. */
/* No background, border or padding of its own: the bubble already is the card,
   and nesting a second one inside it left a frame of dead space on every side. */
.voicenote{display:flex;align-items:center;gap:11px;width:246px;max-width:100%;
  margin:1px 0 3px}
.vn-audio{display:none}
.vn-play{flex:none;width:34px;height:34px;border-radius:50%;cursor:pointer;
  border:none;background:var(--ember);color:var(--on-ember);line-height:1;padding:0;
  display:flex;align-items:center;justify-content:center;transition:.15s;
  -webkit-tap-highlight-color:transparent}
.vn-play:hover{background:var(--ember-deep);transform:scale(1.06)}
/* the whole track is the hit area; the visible line is thinner than the finger */
.vn-track{flex:1;min-width:0;height:18px;cursor:pointer;position:relative;
  display:flex;align-items:center}
.vn-track::before{content:"";position:absolute;left:0;right:0;height:3px;
  border-radius:2px;background:var(--line)}
.vn-fill{position:relative;height:3px;border-radius:2px;width:0;
  background:var(--ember-soft);transition:width .1s linear}
.voicenote.playing .vn-fill{background:var(--ember)}
.vn-time{flex:none;font-family:'Fraunces',serif;font-size:12px;color:var(--muted);
  font-variant-numeric:tabular-nums;min-width:34px;text-align:right}

/* on her side of the thread the bubble is ember, so the player inverts */
.thread.person .steer .vn-play{background:var(--on-ember);color:var(--ember)}
.thread.person .steer .vn-play:hover{background:var(--paper)}
.thread.person .steer .vn-track::before{background:rgba(255,255,255,.3)}
.thread.person .steer .vn-fill{background:rgba(255,255,255,.75)}
.thread.person .steer .voicenote.playing .vn-fill{background:var(--on-ember)}
.thread.person .steer .vn-time{color:rgba(255,255,255,.8)}

.voice-pending{display:flex;align-items:center;gap:8px;width:270px;max-width:100%;
  padding:10px 14px;margin:2px 0 5px;border-radius:14px;
  border:1px dashed var(--line);background:var(--card);
  color:var(--muted);font-size:14px;font-style:italic;
  animation:pulse 1.4s ease-in-out infinite}
.thread.person .steer .voice-pending{border-color:rgba(255,255,255,.35);
  background:rgba(255,255,255,.12);color:rgba(255,255,255,.85)}
.img-pending{width:100%;max-width:360px;height:130px;border-radius:14px;border:1px dashed var(--line);
  background:var(--card);display:flex;align-items:center;justify-content:center;color:var(--muted);
  font-size:14px;font-style:italic;margin:0 0 4px;animation:pulse 1.4s ease-in-out infinite}
@keyframes pulse{0%,100%{opacity:.55}50%{opacity:1}}

/* click-to-zoom overlay for photos and the persona avatar (wired up in app.js) */
.lightbox{position:fixed;inset:0;z-index:60;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:16px;cursor:zoom-out;
  padding:calc(64px + env(safe-area-inset-top)) 20px calc(26px + env(safe-area-inset-bottom));
  background:var(--lb-backdrop);backdrop-filter:blur(7px);
  opacity:0;visibility:hidden;transition:opacity .22s ease,visibility .22s}
.lightbox.open{opacity:1;visibility:visible}
.lightbox img{max-width:min(100%,920px);max-height:100%;min-height:0;flex:0 1 auto;
  border-radius:18px;cursor:default;
  box-shadow:0 18px 60px rgba(0,0,0,.45),0 0 0 1px var(--lb-ring);
  opacity:0;transform:scale(.94);
  transition:opacity .2s ease,transform .26s cubic-bezier(.2,.85,.3,1)}
.lightbox.open img{opacity:1;transform:scale(1)}
/* an explicit ✕, because backdrop-tap-to-close is invisible on a phone */
.lb-close{position:absolute;top:calc(12px + env(safe-area-inset-top));right:14px;
  width:44px;height:44px;border-radius:50%;cursor:pointer;
  border:1px solid var(--lb-edge);background:var(--lb-surface);
  color:var(--lb-ink);font-size:19px;line-height:1;
  display:flex;align-items:center;justify-content:center;
  -webkit-tap-highlight-color:transparent;transition:.18s}
.lb-close:hover{background:rgba(var(--ember-rgb),.6);border-color:var(--ember-soft)}
/* the avatar gallery: page through every photo this persona has ever had */
.lb-nav{flex:none;display:flex;align-items:center;gap:14px;
  font-family:'Fraunces',serif;font-size:13px;letter-spacing:.1em;color:var(--lb-ink)}
.lb-prev,.lb-next{width:38px;height:38px;border-radius:50%;cursor:pointer;
  border:1px solid var(--lb-edge);background:var(--lb-surface);
  color:var(--lb-ink);font-size:19px;line-height:1;
  display:flex;align-items:center;justify-content:center;transition:.18s;
  -webkit-tap-highlight-color:transparent}
.lb-prev:hover:not(:disabled),.lb-next:hover:not(:disabled){
  background:rgba(var(--ember-rgb),.6);border-color:var(--ember-soft)}
.lb-prev:disabled,.lb-next:disabled{opacity:.3;cursor:default}
.lb-acts{flex:none;display:flex;flex-wrap:wrap;gap:9px;justify-content:center}
/* One button. The five used to be five rules that had drifted apart -- Delete
   alone had an 11px radius and its own padding, because it was added last and
   copied the wrong neighbour. Only the modifier differs now. */
.lb-btn{display:inline-flex;align-items:center;justify-content:center;gap:9px;
  font-family:'Fraunces',serif;font-size:15px;line-height:1;
  color:var(--lb-ink);background:var(--lb-surface);border:1px solid var(--lb-edge);
  border-radius:999px;padding:12px 20px;min-height:44px;cursor:pointer;transition:.2s;
  text-decoration:none;-webkit-tap-highlight-color:transparent}
.lb-btn:hover{background:rgba(var(--ember-rgb),.6);border-color:var(--ember-soft)}
.lb-btn .ico{width:17px;height:17px;flex:none}
/* the affirmative action leads: promoting a photo, choosing a new one */
.lb-btn.is-primary{background:var(--ember);border-color:var(--ember);color:var(--on-ember)}
.lb-btn.is-primary:hover{background:var(--ember-deep);border-color:var(--ember-deep)}
/* Delete unlinks the file. It reads as destructive before it is armed, not after,
   and it sits a thumb-width from the arrows you page the gallery with. */
.lb-btn.is-danger{color:var(--lb-danger);border-color:var(--lb-danger)}
.lb-btn.is-danger:hover{background:var(--lb-danger);border-color:var(--lb-danger);
  color:var(--on-ember)}
.lb-btn.is-danger.armed{background:var(--lb-danger);border-color:var(--lb-danger);
  color:var(--on-ember)}
/* Desktop has hover, so the title attribute carries the label and the row stays
   quiet. A phone has no hover at all, so it gets the words. */
.lb-lab{display:none}
@media (max-width:640px){
  .lb-lab{display:inline}
  .lb-btn{padding:12px 18px}
}

body.lb-open{overflow:hidden}
@media (prefers-reduced-motion:reduce){
  .hero::before,.startcard::before{animation:none}
  .modebtn{animation:none}
  .lightbox,.lightbox img{transition-duration:.01ms}
  .lightbox img{transform:none}
}

/* quoted reply header inside a bubble */
.quote{font-size:13px;opacity:.72;border-left:2px solid currentColor;padding-left:8px;
  margin-bottom:5px;white-space:pre-wrap;max-height:2.7em;overflow:hidden;line-height:1.3}

/* reaction chip tucked under the bubble */
.rchip{font-size:13px;background:var(--card);border:1px solid var(--line);border-radius:999px;
  padding:1px 7px;margin-top:-5px;box-shadow:0 1px 2px rgba(var(--shade-rgb),.1);position:relative;z-index:1}

/* persistent react/reply buttons under each bubble (work on touch too) */
.mtools{position:relative;display:flex;align-items:center;gap:5px;margin-top:4px}
.tact{background:var(--card);border:1px solid var(--line);border-radius:999px;cursor:pointer;
  font-size:13px;line-height:1;padding:4px 9px;color:var(--ink-soft);opacity:.7;transition:.12s}
.tact:hover{opacity:1;border-color:var(--ember-soft);color:var(--ember)}
/* emoji picker, opened by the react button; absolute so it adds no layout height */
.repop{position:absolute;bottom:100%;margin-bottom:5px;z-index:5;display:none;
  align-items:center;gap:1px;background:var(--card);border:1px solid var(--line);
  border-radius:999px;padding:3px 7px;box-shadow:var(--shadow)}
.msgwrap.them .repop{left:0}
.msgwrap.me .repop{right:0}
.repop.open{display:flex}
.remoji{border:none;background:none;cursor:pointer;font-size:20px;line-height:1;
  padding:3px 4px;border-radius:50%;transition:.1s}
.remoji:hover{background:var(--paper-2);transform:scale(1.2)}

/* swipe control on the latest reply: ‹ n/N › */
.swipes{display:flex;align-items:center;gap:8px;margin-top:5px}
.msgwrap.me .swipes{align-self:flex-end}
.swarr{border:1px solid var(--line);background:var(--card);color:var(--ink-soft);
  min-width:26px;height:22px;border-radius:7px;cursor:pointer;font-size:14px;line-height:1;
  transition:.12s;padding:0}
.swarr:hover:not(:disabled){border-color:var(--ember-soft);color:var(--ember)}
.swarr:disabled{opacity:.35;cursor:default}
.swnum{font-size:12px;color:var(--muted);font-family:'Fraunces',serif}

/* ⋯ action menu (regenerate, delete, ...): a small vertical popover */
.menupop{position:absolute;bottom:100%;margin-bottom:5px;z-index:6;display:none;
  flex-direction:column;min-width:160px;background:var(--card);border:1px solid var(--line);
  border-radius:12px;padding:5px;box-shadow:var(--shadow)}
.msgwrap.them .menupop{left:0}
.msgwrap.me .menupop{right:0}
.menupop.open{display:flex}
.mitem{border:none;background:none;text-align:left;cursor:pointer;white-space:nowrap;
  font-family:'EB Garamond',serif;font-size:15px;color:var(--ink);
  padding:7px 10px;border-radius:8px;transition:.1s}
.mitem:hover{background:var(--paper-2);color:var(--ember)}
.mdanger:hover{color:var(--danger)}

/* inline editing (all modes). Non-person messages get a hover "edit" link. */
.msgrow{position:relative}
.editlink{border:none;background:none;color:var(--muted);font-family:'Fraunces',serif;
  font-size:12px;letter-spacing:.04em;cursor:pointer;padding:2px 4px;opacity:0;transition:.15s}
.msgrow:hover .editlink{opacity:.55}
.editlink:hover{opacity:1;color:var(--ember)}
@media (hover:none){.editlink{opacity:.4}}
/* the prose-mode action row: same actions as the bubble toolbar, worded quietly
   so they sit under a paragraph without competing with it. Normal flow, not a
   negative margin -- pulling it up collided with the swipe control on the last
   reply, which is the one message that has both. */
.prosetools{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 24px -4px}
.msgrow>.prose,.msgrow>.steer{margin-bottom:6px}
.msgrow>.swipes{margin-bottom:2px}
.edanger:hover{color:var(--ember)}
/* The composer is anchored to the visual viewport, so with a keyboard up it sits
   ON TOP of the thread -- which put it over the edit box and its Save buttons
   whenever the message being edited was near the bottom. You cannot send a
   message while editing one, so it simply goes away for the duration. :has()
   means this clears itself when the form is swapped back to a bubble, with no
   state to get stuck, and keyboardAnchor's height measurement follows because a
   hidden bar measures zero. */
body:has(.msgedit) .compose{display:none}
.msgedit{margin:0 0 20px}
.thread.person .msgedit{margin:0}
.editbox{width:100%;font-family:'EB Garamond',serif;font-size:18px;line-height:1.6;
  color:var(--ink);background:var(--card);border:1px solid var(--ember-soft);border-radius:12px;
  padding:12px 14px;outline:none;resize:vertical;min-height:78px}
.editbox:focus{box-shadow:0 0 0 3px rgba(var(--ember-soft-rgb),.15)}
.erow{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}
.esave,.ecancel,.eresend{font-family:'Fraunces',serif;font-size:14px;border-radius:9px;
  padding:7px 16px;cursor:pointer;transition:.15s}
.esave{background:var(--ember);color:var(--on-ember);border:none}
.esave:hover{background:var(--ember-deep)}
.ecancel{background:var(--card);color:var(--ink-soft);border:1px solid var(--line)}
.ecancel:hover{color:var(--ember);border-color:var(--ember-soft)}
/* resending rewinds the thread and drops every reply below, so it does not get
   to look like the safe button next to it -- outlined, not filled */
.eresend{background:none;color:var(--ink-soft);border:1px solid var(--line)}
.eresend:hover{background:var(--ember);border-color:var(--ember);color:var(--on-ember)}
.epolish{background:var(--card);border:1px solid var(--line);border-radius:9px;font-size:15px;
  line-height:1;padding:7px 12px;cursor:pointer;color:var(--ink-soft);transition:.15s;margin-left:auto}
.epolish:hover{border-color:var(--ember-soft);color:var(--ember)}
.epolish:disabled{opacity:.6;cursor:default}
.epolish.spin{animation:spin .8s linear infinite}
.efull{font-family:'Fraunces',serif;font-size:14px;background:var(--card);
  border:1px solid var(--line);border-radius:9px;padding:7px 14px;cursor:pointer;
  color:var(--ink-soft);transition:.15s;-webkit-tap-highlight-color:transparent}
/* in full screen it is the way back out, so it stops being the quiet one */
.msgedit.full .efull{margin-left:auto;border-color:var(--ember-soft);color:var(--ember)}
.efull:hover{border-color:var(--ember-soft);color:var(--ember)}

/* full-screen editing. The bubble editor is sized for a typo; rewriting a long
   turn in four lines is miserable. animation:none matters -- .thread>* runs the
   rise keyframes, and a transformed ancestor would make position:fixed resolve
   against the element instead of the viewport. */
.msgedit.full{position:fixed;inset:0;z-index:60;margin:0;animation:none;
  background:var(--paper);border-radius:0;
  padding:calc(14px + env(safe-area-inset-top)) 16px calc(14px + env(safe-area-inset-bottom));
  display:flex;flex-direction:column}
.msgedit.full form{flex:1;min-height:0;display:flex;flex-direction:column}
/* the inline box caps its height so a long turn does not swallow the thread;
   full screen is exactly the case where that cap has to go */
.msgedit.full .editbox{flex:1;min-height:0;max-height:none;resize:none;
  font-size:19px;line-height:1.65}
.msgedit.full .erow{flex:none;margin-top:12px}
/* the thread behind is still there; keep it from scrolling under the overlay */
body.editing-full{overflow:hidden}

/* "replying to..." bar above the composer */
.quotebar{max-width:calc(var(--col) - var(--gutter)*2);margin:0 auto 8px;display:flex;align-items:center;gap:10px;
  background:var(--card);border:1px solid var(--line);border-left:3px solid var(--ember);
  border-radius:10px;padding:8px 12px}
.qtext{flex:1;font-size:14px;color:var(--ink-soft);white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis;font-style:italic}
.qcancel{border:none;background:none;color:var(--muted);font-size:16px;cursor:pointer;padding:2px 6px}
.qcancel:hover{color:var(--ember)}

/* menu button (opens the drawer) */
.menu-btn{font-size:20px;line-height:1;color:var(--ink-soft);background:var(--card);
  border:1px solid var(--line);border-radius:12px;width:42px;height:42px;cursor:pointer;
  display:flex;align-items:center;justify-content:center;transition:.2s}
.menu-btn:hover{border-color:var(--ember-soft);color:var(--ember)}

/* chat bar: the reading view's top bar -- back arrow, persona chip, menu. The
   chip is always there now that nothing above the thread duplicates it, and
   tapping it opens the avatar (app.js). */
.chatbar{gap:10px}
.backbtn{flex:none;font-family:'Fraunces',serif;font-size:30px;line-height:1;
  color:var(--ink-soft);background:var(--card);border:1px solid var(--line);
  border-radius:12px;width:42px;height:42px;
  display:flex;align-items:center;justify-content:center;
  padding-bottom:4px;  /* the ‹ glyph sits low in its box */
  -webkit-tap-highlight-color:transparent;transition:.2s}
.backbtn:hover{border-color:var(--ember-soft);color:var(--ember)}
.bar-persona{position:relative;display:flex;align-items:center;gap:10px;min-width:0;
  color:inherit;text-decoration:none}
/* a portrait takes ~20s, so ring the chip while it is being drawn. The ring is a
   pseudo-element rather than a border on the photo: spinning the img would spin
   her face with it. */
/* a full faint ring with a bright leading arc. A lone arc on transparent looked
   like a stray mark parked beside the avatar rather than a spinner around it. */
.bar-persona.drawing::before{content:"";position:absolute;left:-3px;top:50%;
  width:40px;height:40px;margin-top:-20px;border-radius:50%;pointer-events:none;
  border:2px solid rgba(var(--ember-rgb),.25);border-top-color:var(--ember);
  animation:spin .9s linear infinite}
/* stands in for the photo she does not have yet, so the ring has something to sit around */
.bar-blank{display:block;background:var(--card)}
.bar-avatar{flex:none;width:34px;height:34px;object-fit:cover;border-radius:50%;
  border:1px solid var(--line);transition:border-color .15s}
/* only a chip carrying a photo is worth tapping */
.bar-persona:has(.bar-avatar){cursor:pointer;-webkit-tap-highlight-color:transparent}
.bar-persona:hover .bar-avatar{border-color:var(--ember-soft)}
.bar-name{font-family:'Fraunces',serif;font-weight:500;font-size:18px;color:var(--ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* slide-out drawer + scrim */
.drawer-wrap{position:fixed;inset:0;z-index:20;pointer-events:none;visibility:hidden}
.drawer-wrap.open{pointer-events:auto;visibility:visible}
.scrim{position:absolute;inset:0;background:rgba(var(--shade-rgb),.32);opacity:0;transition:opacity .25s}
.drawer-wrap.open .scrim{opacity:1}
.drawer{position:absolute;top:0;right:0;height:100%;width:min(300px,84vw);
  background:var(--paper-2);border-left:1px solid var(--line);
  box-shadow:-12px 0 40px rgba(var(--shade-rgb),.14);
  padding:22px 20px calc(22px + env(safe-area-inset-bottom));
  display:flex;flex-direction:column;gap:6px;
  /* a short screen (landscape phone) must scroll the panel, not push the foot
     with Log out and Archive off the bottom edge */
  overflow-y:auto;overscroll-behavior:contain;
  transform:translateX(100%);transition:transform .28s cubic-bezier(.4,0,.2,1)}
.drawer-wrap.open .drawer{transform:none}
/* contents arrive just behind the panel, so opening it reads as one movement */
.drawer-wrap.open .drawer>*{animation:drift .34s cubic-bezier(.2,.8,.3,1) both}
.drawer-wrap.open .drawer>*:nth-child(2){animation-delay:.04s}
.drawer-wrap.open .drawer>*:nth-child(3){animation-delay:.08s}
.drawer-wrap.open .drawer>*:nth-child(4){animation-delay:.11s}
.drawer-wrap.open .drawer>*:nth-child(n+5){animation-delay:.14s}
@keyframes drift{from{opacity:0;transform:translateY(9px)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){
  .drawer-wrap.open .drawer>*{animation:none}
  .drawer{transition-duration:.01ms}
}
/* identity is one row: the mark, then your face and name pushed right. It was
   three stacked blocks -- brand, name, and a 101px "Your photo" card with an
   explanatory line -- which put an account setting you touch once above the
   session you came in to use. */
.drawer-top{display:flex;align-items:center;gap:10px;
  margin:0 0 4px;padding-bottom:15px;border-bottom:1px solid var(--line)}
/* a mistyped slash command says so, briefly, where the reply would have gone */
.cmdnote{align-self:center;margin:6px auto;padding:7px 14px;border-radius:999px;
  background:var(--card);border:1px solid var(--ember-soft);color:var(--ember);
  font-family:'Fraunces',serif;font-size:13px;animation:rise .3s ease both}

.drawer-brand{flex:1;min-width:0;font-family:'Fraunces',serif;font-weight:600;font-size:22px;
  display:flex;align-items:center;gap:8px;margin:0}
.drawer-brand .flame{filter:drop-shadow(0 0 6px var(--glow))}
.drawer-you{flex:none;display:flex;align-items:center;gap:8px;min-width:0}
.drawer-who{font-family:'EB Garamond',serif;font-style:italic;color:var(--muted);
  font-size:14px;max-width:96px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* the face is an identity chip here, not a photo manager: small enough to sit on
   one line with the brand. Tapping still opens the lightbox and its uploader. */
.drawer-you .avatar-label,.drawer-you .avatar-img,.drawer-you .avatar-add{
  width:30px;height:30px}
.drawer-you .avatar-add{font-size:13px;border-width:1px}
.drawer-you .avatar-badge{display:none}
/* the three scopes, separated by space rather than another caption */
.drawer-group{display:flex;flex-direction:column;gap:2px;margin:0 0 6px}
.drawer-link{font-family:'Fraunces',serif;font-size:17px;color:var(--ink);
  padding:11px 12px;border-radius:11px;transition:.15s}
.drawer-link:hover{background:var(--card);color:var(--ember)}
.drawer-foot{margin-top:auto;padding-top:12px;border-top:1px solid var(--line);
  display:flex;flex-direction:column;gap:2px}
.drawer-quiet{color:var(--ink-soft)}
/* the appearance row: one tap cycles Auto -> Light -> Dark. The three icons are
   all present and data-state picks which one shows. */
.theme-toggle{display:flex;align-items:center;gap:10px;width:100%;background:none;
  border:none;cursor:pointer;text-align:left;-webkit-tap-highlight-color:transparent}
.theme-toggle .ico{width:18px;height:18px;display:none;opacity:.8}
.theme-toggle[data-state="auto"] .ico-auto,.theme-toggle[data-state="light"] .ico-light,
.theme-toggle[data-state="dark"] .ico-dark{display:block}
.theme-toggle .theme-state{margin-left:auto;font-size:13px;letter-spacing:.06em;
  text-transform:uppercase;color:var(--muted)}
.drawer-cap{font-family:'Fraunces',serif;color:var(--muted);font-size:11px;
  text-transform:uppercase;letter-spacing:.14em;margin:14px 4px 6px}
.drawer-view{margin:0 0 4px}
/* every other session, one tap from anywhere */
.drawer-sessions{margin:2px 0 6px}
.dslist{display:flex;flex-direction:column;gap:1px}
.dsrow{display:flex;align-items:center;gap:9px;padding:8px 10px;border-radius:10px;
  transition:.14s;-webkit-tap-highlight-color:transparent}
.dsrow:hover{background:var(--card)}
.dsi{flex:none;font-size:13px}
.dst{flex:1;min-width:0;font-family:'Fraunces',serif;font-size:15px;color:var(--ink-soft);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dsrow:hover .dst{color:var(--ember)}
/* the one you are already in: marked by fill and weight alone. It had an ember
   bar down its left edge too, which is the accent every generated UI reaches
   for, so it went. */
.dsrow.on{background:var(--card)}
.dsrow.on .dst{color:var(--ink);font-weight:500}
.dsmore{font-family:'Fraunces',serif;font-size:13px;color:var(--muted);
  letter-spacing:.04em;padding-left:10px}
.dsmore:hover{color:var(--ember)}
.switch{width:100%;font-family:'EB Garamond',serif;font-size:15px;color:var(--ink);
  background:var(--card);border:1px solid var(--line);border-radius:11px;padding:10px 12px;
  outline:none;cursor:pointer}
.switch:focus{border-color:var(--ember-soft)}

/* persona avatar -- lives in the drawer's session panel, not above the thread */
.avatarwrap{flex:none;margin:0}
.avatar-label{display:block;width:62px;height:62px;cursor:pointer;position:relative}
.avatar-file{display:none}
.avatar-badge{position:absolute;bottom:-2px;right:-2px;background:var(--ember);color:var(--on-ember);
  font-family:'Fraunces',serif;font-size:11px;min-width:18px;height:18px;border-radius:9px;
  display:flex;align-items:center;justify-content:center;border:2px solid var(--paper);padding:0 3px}
.avatar-img{width:62px;height:62px;object-fit:cover;border-radius:50%;
  border:2px solid var(--line);transition:.15s}
.avatar-label:hover .avatar-img{border-color:var(--ember-soft)}
.avatar-add{display:flex;align-items:center;justify-content:center;width:62px;height:62px;
  border-radius:50%;background:var(--card);border:2px dashed var(--line);color:var(--muted);
  font-size:24px;transition:.15s}
.avatar-label:hover .avatar-add{border-color:var(--ember-soft);color:var(--ember)}

/* the drawer's session card. The one lit object in the panel: it reuses the
   ember wash from the landing-page mode cards, so "the thing you edit" reads as
   raised while everything below it stays flat nav. */
.drawer-session{margin:2px 0 4px}
.drawer-card{position:relative;overflow:hidden;background:var(--card);
  border:1px solid var(--line);border-radius:16px;padding:15px 14px 14px;
  box-shadow:0 1px 2px rgba(var(--shade-rgb),.04)}
.drawer-card::after{content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(260px 90px at 88% -10%,rgba(var(--glow-rgb),.20),transparent 70%)}
.drawer-idrow{display:flex;align-items:center;gap:13px;margin:0 0 13px;position:relative;z-index:1}
.drawer-idrow .avatarwrap{margin:0}
.drawer-meta{display:flex;flex-direction:column;gap:3px;min-width:0;margin:0}
.drawer-mode{font-family:'Fraunces',serif;font-size:13px;letter-spacing:.1em;
  text-transform:uppercase;color:var(--ink-soft);white-space:nowrap}
.drawer-mode .mi{margin-right:7px;letter-spacing:0}
.drawer-sub{font-size:11px;letter-spacing:.12em;color:var(--muted)}
.drawer-title{position:relative;z-index:1;width:100%;
  font-family:'Fraunces',serif;font-weight:500;font-size:19px;line-height:1.25;
  color:var(--ink);background:var(--paper-2);border:1px solid var(--line);
  border-radius:11px;padding:9px 12px;outline:none;transition:.15s}
.drawer-title::placeholder{color:var(--muted);font-style:italic}
.drawer-title:focus{border-color:var(--ember-soft);box-shadow:0 0 0 3px rgba(var(--ember-soft-rgb),.15)}

/* the persona card, admin only: a drawer link that opens a modal. Nine fields
   is a form, and the drawer is a list of places to go -- putting the form in it
   made the drawer a scroll. Native <dialog>, so the backdrop and the top layer
   come from the browser and it escapes the drawer's own stacking context. */
.pc-slot{display:contents}
.pc-open{display:flex;align-items:baseline;gap:9px;width:100%;text-align:left}
.pcl-t{font-family:'Fraunces',serif;font-size:17px;flex:none}
.pcl-n{font-family:'EB Garamond',serif;font-style:italic;font-size:13px;color:var(--muted);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
.pc-open:hover .pcl-n{color:var(--ember)}

.pc-modal{width:min(560px,calc(100vw - 32px));max-height:min(86vh,760px);
  padding:0;border:1px solid var(--line);border-radius:18px;background:var(--paper);
  color:var(--ink);overflow:hidden;box-shadow:0 24px 60px rgba(var(--shade-rgb),.22)}
/* only while open, because `display` is also what closes a <dialog>. Flex so the
   body takes the leftover height itself -- a max-height calculated off the
   header's guessed pixel height clipped Regenerate below the fold. */
.pc-modal[open]{display:flex;flex-direction:column}
/* showModal() does not stop the page behind from scrolling; same lock the
   lightbox uses */
body.pc-lock{overflow:hidden}
.pc-modal::backdrop{background:rgba(var(--shade-rgb),.5);backdrop-filter:blur(2px)}
/* a <dialog> does not stop the page behind it scrolling, so the wheel ran the
   thread under the backdrop. Done with :has() rather than a class toggled on
   open, because the dialog also closes on Esc and on a backdrop click -- a
   class would have to be unset from three places and would eventually desync. */
body:has(dialog[open]){overflow:hidden}
.pc-head{flex:none;display:flex;align-items:center;gap:12px;padding:16px 18px 13px;
  border-bottom:1px solid var(--line);background:var(--paper-2)}
.pc-title{flex:1;min-width:0;margin:0;font-family:'Fraunces',serif;font-weight:600;
  font-size:20px;line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pc-x{flex:none;width:32px;height:32px;border-radius:50%;display:flex;align-items:center;
  justify-content:center;color:var(--muted);background:transparent;transition:.15s}
.pc-x:hover{background:var(--card);color:var(--ember)}
/* contain: scrolling the card to its end must not hand the rest of the wheel
   gesture to the page underneath */
/* The body sizes itself and caps itself, rather than flex:1 + min-height:0
   filling whatever the dialog has. A top-layer <dialog> is height:fit-content
   by UA style, and Safari resolves fit-content from a min-height:0 overflow
   child as ZERO -- so the dialog came out the height of its header and the
   card was a header with a sliver of content under it. Chrome uses
   max-content for the same computation and looked fine. The cap is the
   dialog's max-height minus the header (~64px), so the total never exceeds it
   and the body scrolls inside when it would. */
.pc-body{flex:0 1 auto;max-height:calc(min(86vh,760px) - 64px);overflow-y:auto;
  overscroll-behavior:contain;padding:16px 18px 18px}
.pc-form{display:grid;grid-template-columns:1fr 1fr;gap:11px}
/* the three prose fields run the full width; the six short ones pair up */
.pc-field{display:flex;flex-direction:column;gap:5px;min-width:0}
.pc-field:nth-child(n+7){grid-column:1 / -1}
.pc-lab{font-family:'Fraunces',serif;font-size:10px;text-transform:uppercase;
  letter-spacing:.13em;color:var(--muted)}
.pc-in,.pc-area{width:100%;font-family:'EB Garamond',serif;font-size:16px;color:var(--ink);
  background:var(--paper-2);border:1px solid var(--line);border-radius:10px;padding:9px 11px;
  outline:none;transition:.15s}
/* the bare textarea rule caps height at 180px; these want to grow with the prose */
.pc-area{resize:vertical;line-height:1.5;max-height:none}
.pc-in:focus,.pc-area:focus{border-color:var(--ember-soft);box-shadow:0 0 0 3px rgba(var(--ember-soft-rgb),.15)}
.pc-regen{display:flex;align-items:center;justify-content:center;gap:8px;width:100%;
  margin-top:14px;padding:11px;border-radius:11px;font-family:'Fraunces',serif;font-size:15px;
  color:var(--ink-soft);background:var(--card);border:1px solid var(--line);transition:.15s}
.pc-regen:hover{border-color:var(--ember-soft);color:var(--ember)}
.pc-regen:disabled{opacity:.55;cursor:default}
/* the profile card: face, name, mode, then the photo grid. The head is centred
   like a contact card; the grid is three across because a phone is ~360px of
   dialog and 3 x 110px tiles is the WhatsApp density everyone already reads. */
.pf-page{padding:26px 0 40px}
/* the model beside the gauge, and its picker */
.usage-model{margin-left:10px;padding:2px 9px;border-radius:999px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:11px;color:var(--muted);background:transparent;border:1px solid var(--line);cursor:pointer;transition:.15s}
.usage-model:hover{color:var(--ember);border-color:var(--ember-soft)}
.mp-body{padding:12px 12px 14px;display:flex;flex-direction:column;gap:10px;min-height:0}
.mp-q{width:100%;font-family:'EB Garamond',serif;font-size:16px;color:var(--ink);background:var(--paper-2);
  border:1px solid var(--line);border-radius:10px;padding:9px 11px;outline:none}
.mp-q:focus{border-color:var(--ember-soft)}
.mp-list{overflow-y:auto;min-height:0;display:flex;flex-direction:column;gap:2px}
.mp-row{display:flex;flex-direction:column;align-items:flex-start;gap:2px;width:100%;text-align:left;
  padding:8px 10px;border-radius:9px;background:transparent;border:1px solid transparent;cursor:pointer;color:var(--ink)}
.mp-row:hover{background:var(--card)}
.mp-row.is-current{border-color:var(--ember-soft)}
.mp-id{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13px}
.mp-meta{font-family:'EB Garamond',serif;font-size:12px;color:var(--muted)}
.mp-empty{color:var(--muted);font-style:italic}
/* a refused seed or card: said plainly, in the danger colour, above the box */
.start-refused,.pc-note{font-family:'EB Garamond',serif;font-size:16px;color:var(--lb-danger,#c0503c);
  margin:0 0 12px}
.pf-id{display:flex;flex-direction:column;align-items:center;gap:8px;text-align:center}
.pf-photo{width:128px;height:128px;border-radius:50%;object-fit:cover;
  border:2px solid var(--line);cursor:pointer;transition:.15s;
  -webkit-tap-highlight-color:transparent}
.pf-photo:hover{border-color:var(--ember-soft)}
.pf-none{display:flex;align-items:center;justify-content:center;background:var(--paper-2);
  color:var(--muted);cursor:default}
.pf-none .ico{width:34px;height:34px}
.pf-mode{margin-top:6px}
.pf-meta{font-family:'EB Garamond',serif;font-style:italic;font-size:14px;color:var(--muted)}
.pf-persona{margin-top:16px;padding:11px 12px;border:1px solid var(--line);border-radius:11px;
  background:var(--card)}
.pf-cap{margin:22px 0 10px}
.pf-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:4px}
.pf-tile{width:100%;aspect-ratio:1;object-fit:cover;border-radius:6px;cursor:pointer;
  background:var(--paper-2);transition:.15s;-webkit-tap-highlight-color:transparent}
.pf-tile:hover{opacity:.85}
.pf-empty{margin:26px 0 8px;text-align:center;font-family:'EB Garamond',serif;font-style:italic;
  color:var(--muted)}
@media (max-width:480px){
  /* on a phone the pairs stop fitting long before the modal does */
  .pc-form{grid-template-columns:1fr}
  .pc-field:nth-child(n+7){grid-column:auto}
}

/* archive: a link like the rest until you arm it, then unmistakably ember */
/* it lives inside "This session" now, one row under a text field, so it has to
   read as destructive at rest rather than only once armed. The two-tap arming
   stays: archiving moves a session out from under whoever is reading it. */
.drawer-danger{width:100%;display:flex;align-items:center;gap:9px;text-align:left;
  font-family:'Fraunces',serif;font-size:17px;
  color:var(--ember);background:none;border:none;cursor:pointer;
  -webkit-tap-highlight-color:transparent}
.drawer-danger svg{flex:none;opacity:.85}
.drawer-danger:hover{background:var(--card);color:var(--ember)}
.drawer-danger.armed{background:var(--ember);color:var(--on-ember)}
.drawer-danger.armed:hover{background:var(--ember-deep);color:var(--on-ember)}

/* archived sessions: folded away on the landing page, not hidden */
.arch summary{cursor:pointer;list-style:none;display:inline-flex;align-items:center;gap:7px;
  -webkit-tap-highlight-color:transparent}
.arch summary::-webkit-details-marker{display:none}
.arch summary::before{content:"›";display:inline-block;transition:transform .18s;
  font-size:15px;line-height:1}
.arch[open] summary::before{transform:rotate(90deg)}
.arch summary:hover{color:var(--ember)}
.arch .slist{margin-top:8px}

/* login / setup card */
.auth{max-width:380px;margin:70px auto 0;padding:0 22px;text-align:center}
.auth h1{font-family:'Fraunces',serif;font-weight:400;font-size:38px;margin:0 0 6px}
.auth .flame{filter:drop-shadow(0 0 6px var(--glow))}
.auth p{color:var(--ink-soft);font-style:italic;margin:0 0 26px}
.auth form{display:flex;flex-direction:column;gap:12px;background:var(--card);
  border:1px solid var(--line);border-radius:18px;padding:24px;box-shadow:var(--shadow)}
.auth input,.auth select{font-family:'EB Garamond',serif;font-size:17px;color:var(--ink);background:var(--paper-2);
  border:1px solid var(--line);border-radius:11px;padding:12px 14px;outline:none;min-width:0;max-width:100%}
.auth input:focus,.auth select:focus{border-color:var(--ember-soft);box-shadow:0 0 0 3px rgba(var(--ember-soft-rgb),.15)}
.auth button{font-family:'Fraunces',serif;font-size:16px;color:var(--on-ember);background:var(--ember);
  border:none;border-radius:11px;padding:12px;cursor:pointer;transition:.2s}
.auth button:hover{background:var(--ember-deep)}
.auth .err{color:var(--ember);font-style:italic;font-size:15px;margin:0 0 6px}

/* admin: users, each with their sessions */
.admin{max-width:560px}
.ublock{margin:0 0 26px}
.urow{display:flex;align-items:baseline;gap:12px;padding:10px 4px 8px;
  border-bottom:1px solid var(--line);margin:0 0 4px}
.urow .un{flex:1;font-family:'Fraunces',serif;font-size:20px}
.urow .ub{font-size:13px;color:var(--muted);font-style:italic}
.admin-empty{color:var(--muted);font-style:italic;font-size:15px;padding:8px 4px;margin:0}
.addcard{margin:40px 0 0;padding-top:26px;border-top:1px solid var(--line)}
.addcard .drawer-cap{margin:0 0 12px 2px}

/* admin peeking at someone else's session (read-only) */
.read.peek{padding-bottom:80px}
.peek-note{font-family:'Fraunces',serif;font-size:12px;letter-spacing:.06em;
  color:var(--ember);background:rgba(var(--ember-rgb),.08);border:1px solid var(--ember-soft);
  border-radius:999px;padding:6px 14px;display:inline-block;margin:0 0 18px}
.peek-title{font-family:'Fraunces',serif;font-weight:500;font-size:27px;line-height:1.2;
  color:var(--ink);margin:0 0 22px}

/* mobile */
@media (max-width:640px){
  body{font-size:18px}
  :root{--gutter:16px}
  .bar{height:56px} .brand{font-size:20px}
  .hero{padding:34px 0 14px}
  .hero h1{font-size:32px} .hero p{font-size:18px}
  .modegrid{gap:10px;padding:12px 0 28px}
  .modebtn{min-height:104px;padding:15px 10px;gap:7px}
  .mb-i{font-size:27px}
  .mb-l{font-size:17px}
  .startcard{margin-top:3vh}
  .start-icon{font-size:44px}
  .start-title{font-size:31px}
  .start-blurb{font-size:17px;margin-bottom:22px}
  .begin{padding:0 14px}
  .read{padding-block:14px 150px}
  .prose{font-size:19px;line-height:1.72}
  .tag{margin-bottom:16px}
  /* sitting on the keyboard, so the breathing room above it is what costs
     screen; the bottom padding is only the home indicator */
  .compose{padding:10px var(--gutter) calc(8px + env(safe-area-inset-bottom))}
  .hint{display:none}
}

/* icon sizes, per control */
.menu-btn .ico{width:19px;height:19px}
.backbtn .ico{width:22px;height:22px}
.tact .ico{width:16px;height:16px}
.systool .ico{width:14px;height:14px}
.swarr .ico{width:15px;height:15px}
.mitem .ico{width:16px;height:16px;opacity:.75}
.qcancel .ico{width:15px;height:15px}
.polish .ico{width:19px;height:19px}
.send .ico{width:20px;height:20px;stroke-width:2.4}
.vn-play .ico{width:14px;height:14px}
.avatar-add .ico{width:22px;height:22px;stroke-width:1.6}
.img-pending .ico,.voice-pending .ico{width:16px;height:16px}
/* labelled controls line their icon up with the text */
.mitem{display:flex;align-items:center;gap:9px}
.img-pending,.voice-pending{align-items:center}
/* the glyphs these replaced were centred by font metrics; SVGs need the box to do it */
.backbtn{padding-bottom:0}
