:root{color-scheme:dark;font-family:var(--body);background:var(--bg);color:var(--text)}
/* An icon keeps a square of its own size from the first paint: its font draws the name ("send") as a glyph only once loaded, and the name's text would take another width until then. */
.material-symbols-outlined{width:1em;height:1em;overflow:hidden;flex:none}
*{box-sizing:border-box}html,body,#app{margin:0;min-height:100%;height:100%}body{background:radial-gradient(circle at 70% 0,var(--surface-warm-high) 0,transparent 32%),var(--bg);font-size:var(--size-story)}button,input,textarea,select{font:inherit;color:inherit}button{border:1px solid var(--line);border-radius:var(--radius-lg);background:var(--surface-warm);padding:.65rem .9rem;cursor:pointer}button:where(:not(.item-row,.doll-slot,.magic-ability,.campaign-title)){font:500 var(--size-ui)/1.25 var(--head);letter-spacing:.02em}button:hover{border-color:var(--accent)}button:focus-visible{border-color:var(--accent);outline:2px solid var(--accent);outline-offset:2px}.primary{background:linear-gradient(var(--accent-850),var(--accent-950));border-color:var(--accent-600);color:var(--accent-100);font-size:var(--size-compact);font-weight:600}.material-symbols-outlined{font-family:"Material Symbols Outlined";font-size:21px;vertical-align:middle}.topbar{height:calc(70px + env(safe-area-inset-top));display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--line);padding:calc(8px + env(safe-area-inset-top)) max(18px,env(safe-area-inset-right)) 8px max(18px,env(safe-area-inset-left));background:rgb(var(--bg-rgb) / .94)}.campaign-title{border:0;background:none;text-align:left;padding:4px}.campaign-title small{display:block;color:var(--muted);font:var(--size-caption) var(--head);text-transform:uppercase}.campaign-title b{font:600 var(--size-lead) var(--head);color:var(--accent)}.top-actions{display:flex;gap:var(--space-4);align-items:center}.connection{font:var(--size-label) var(--head);color:var(--muted)}.app-layout{display:grid;grid-template-columns:minmax(0,1fr) minmax(360px,31vw);height:calc(100% - 70px - env(safe-area-inset-top))}.story-column{display:flex;flex-direction:column;min-width:0}.empty-state{margin:auto;text-align:center;padding:2rem}
/* Not drawn until startup knows whether an adventure is open (src/bootstrap.mjs sets data-booted), so a returning player never sees it flash; drawn anyway after 4 s if startup hangs. */
html:not([data-booted]) #empty-state{animation:boot-reveal 0s 4s both}
@keyframes boot-reveal{from{visibility:hidden}to{visibility:visible}}.empty-state h1{font:600 clamp(var(--size-display),6vw,52px) var(--head);letter-spacing:.12em}.empty-state h1 span{color:var(--accent)}.chat{flex:1;overflow:auto;padding:28px max(20px,6vw)}.message{max-width:820px;margin:0 auto 22px;line-height:1.6}.message p{margin:.45em 0}.composer{display:flex;gap:var(--space-5);padding:12px max(15px,4vw,env(safe-area-inset-right)) calc(12px + env(safe-area-inset-bottom)) max(15px,4vw,env(safe-area-inset-left));border-top:1px solid var(--line);background:var(--surface)}.composer textarea{flex:1;resize:none;max-height:180px;padding:12px 14px;border:1px solid var(--stone-800);border-radius:var(--radius-xl);background:var(--field)}.composer #send{width:48px;height:48px;border-radius:var(--radius-round);padding:0}.drawer{border-left:1px solid var(--line);padding-right:env(safe-area-inset-right);background:rgb(var(--surface-low-rgb) / .94);overflow:hidden;display:flex;flex-direction:column}.panel-tabs,.subtabs{display:flex;border-bottom:1px solid var(--line)}.panel-tabs button,.subtabs button{flex:1;border:0;border-radius:0;background:none;color:var(--muted);font:var(--size-label) var(--head);padding:14px 5px}.panel-tabs button.active,.subtabs button.active{color:var(--accent);box-shadow:inset 0 -2px var(--accent)}.panel-tabs span{display:block;margin-bottom:4px}.panel-content,.inventory-content{overflow:auto;padding:18px}.status-card,.inventory-card,.lore-card{border:1px solid var(--line);border-radius:var(--radius-2xl);background:linear-gradient(135deg,rgb(var(--accent-900-rgb) / .45),rgb(var(--surface-low-rgb) / .8));padding:18px;margin-bottom:16px}.status-card h2,.inventory-card h2,.lore-card h2{font:500 var(--size-lead) var(--head);color:var(--accent);letter-spacing:.08em;text-transform:uppercase;margin:0}.status-card header{display:flex;align-items:center;gap:var(--space-6);margin-bottom:15px}.empty{color:var(--muted);font-style:italic}.stash-card.remote{opacity:.68}.stash-card p{color:var(--muted)}.mobile-nav{display:none}dialog{border:0;padding:0;background:transparent;max-width:min(680px,94vw);max-height:90vh}dialog::backdrop{background:rgb(var(--black-rgb) / .78);backdrop-filter:blur(3px)}.dialog-card{display:flex;flex-direction:column;gap:var(--space-7);background:var(--surface);border:1px solid var(--accent-600);border-radius:var(--radius-2xl);padding:20px;min-width:min(420px,90vw);max-height:88vh;overflow:auto}.dialog-card header{display:flex;align-items:center;justify-content:space-between}.dialog-card h2{margin:0;color:var(--accent);font:500 var(--size-story) var(--head);text-transform:uppercase}.icon{border:0;background:none;font-size:28px;padding:0 8px}.dialog-card label{display:flex;flex-direction:column;gap:var(--space-3);color:var(--muted)}.dialog-card input,.dialog-card textarea,.dialog-card select{border:1px solid var(--stone-750);border-radius:var(--radius-md);background:var(--field);padding:9px;color:var(--text)}.dialog-card textarea{min-height:75px}.dialog-card footer{display:flex;justify-content:flex-end;gap:var(--space-5)}.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-6)}.form-grid .full{grid-column:1/-1}.hint{color:var(--muted);font-size:var(--size-small)}.sync-actions{display:flex;gap:var(--space-5)}.toast{position:fixed;left:50%;bottom:90px;transform:translate(-50%,20px);opacity:0;pointer-events:none;background:var(--accent-900);border:1px solid var(--accent-600);border-radius:var(--radius-lg);padding:9px 14px;transition:.2s;z-index:20}.toast.show{opacity:1;transform:translate(-50%,0)}.item-detail p{margin:.4em 0}.tags{display:flex;flex-wrap:wrap;gap:var(--space-3)}.tag{border:1px solid var(--stone-700);border-radius:var(--radius-pill);padding:3px 8px;color:var(--muted);font-size:var(--size-ui)}
@media(max-width:800px){body{font-size:var(--size-lead)}.topbar{height:61px}.app-layout{display:block;height:calc(100% - 61px - 67px)}.story-column,.drawer{height:100%}.drawer{display:none;border:0}.app-layout.show-panel .story-column{display:none}.app-layout.show-panel .drawer{display:flex}.panel-tabs{display:none}.mobile-nav{position:fixed;display:flex;bottom:0;left:0;right:0;height:67px;padding-bottom:env(safe-area-inset-bottom);background:var(--surface);border-top:1px solid var(--line);z-index:10}.mobile-nav button{flex:1;border:0;border-radius:0;background:none;color:var(--muted);font:var(--size-tiny) var(--head);padding:7px 2px}.mobile-nav span{display:block;margin-bottom:3px}.mobile-nav button.active{color:var(--accent)}.chat{padding:20px 18px}.composer{padding:10px}.connection{display:none}.panel-content{padding:12px}.form-grid{grid-template-columns:1fr}.form-grid .full{grid-column:auto}.dialog-card{min-width:92vw}}

/* v6.0.1 responsive hardening: desktop and portrait mobile are first-class layouts.
   On notched screens (viewport-fit=cover) the top bar, chat bar, drawer and
   bottom bar keep clear of the safe-area insets; env() is 0 everywhere else. */
html,body,#app{width:100%;max-width:100%;overflow-x:clip}
.topbar,.campaign-title,.top-actions,.app-layout,.story-column,.drawer,.panel-content,.inventory-content{min-width:0}
.topbar{gap:var(--space-6);position:relative;z-index:20}
.campaign-title{flex:1 1 auto;overflow:hidden}
.campaign-title b{display:block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.top-actions{flex:0 0 auto}
.story-column,.drawer{overflow:hidden}
/* Chat bar: one row (narrator menu button, action, Send); the menu opens above it.
   Send and Stop are round, drawn like the narrator button: a gold icon from the
   icon font on the dark warm surface, inside a gold ring. */
.composer[hidden]{display:none!important}
.composer{--composer-pad:max(15px,4vw,env(safe-area-inset-left));position:relative;display:grid;grid-template-columns:44px minmax(0,1fr) 48px;align-items:end}
.composer textarea{grid-column:2;display:block;width:100%;min-width:0;line-height:1.35}
/* The action box takes focus in the theme, as the creator's fields do, not the browser's white ring. */
.composer textarea:focus{outline:none;border-color:var(--accent-450);box-shadow:0 0 0 2px rgb(var(--accent-450-rgb) / .14)}
.composer #send,.composer .turn-stop{grid-column:3;display:grid;place-items:center;width:48px;height:48px;padding:0;border-color:var(--accent-600);border-radius:var(--radius-round);background:var(--surface-warm);color:var(--accent)}
.composer .send-glyph{font-size:22px;transform:rotate(-90deg)}
/* The tools button opens the sheet (styles/action-pickers.css); open, its +
   turns to a close mark. With the NSFW narrator on it wears an 18+ mark. */
.tools-button{grid-column:1;position:relative;display:grid;place-items:center;width:44px;height:44px;margin-bottom:2px;padding:0;border-color:var(--accent-600);border-radius:var(--radius-round);background:var(--surface-warm);color:var(--accent)}
.tools-button[aria-expanded=true]{border-color:var(--accent);background:var(--accent);color:var(--on-accent)}
.tools-glyph{font-size:24px;transition:transform .15s}
.tools-button[aria-expanded=true] .tools-glyph{transform:rotate(45deg)}
.tools-adult{display:none;position:absolute;top:-6px;right:-8px;padding:1px 4px;border-radius:var(--radius-sm);background:var(--nsfw-600);color:var(--nsfw-50);font:700 var(--size-micro)/1.3 var(--head);letter-spacing:.02em;box-shadow:0 0 0 2px var(--surface)}
@media(prefers-reduced-motion:reduce){.tools-glyph{transition:none}}
/* The Narrator tab of the tools sheet. */
.narration-menu{display:flex;flex-direction:column;gap:var(--space-3);min-height:0;overflow-y:auto;padding:2px 12px 16px}
.narration-menu .narration-toggle{display:flex;align-items:center;gap:var(--space-5);height:44px;padding:0 8px;border:0;border-radius:var(--radius-md);background:transparent;color:var(--text-dim);font:600 var(--size-label) var(--head);white-space:nowrap}
.narration-track{display:flex;align-items:center;width:30px;height:18px;padding:2px;border:1px solid var(--grey-650);border-radius:var(--radius-pill);background:var(--grey-850);flex-shrink:0}
.narration-track span{width:12px;height:12px;border-radius:var(--radius-round);background:var(--grey-350);transition:transform .15s}
.narration-menu-caption{flex-shrink:0;color:var(--accent-550);font:600 var(--size-tiny) var(--head);letter-spacing:.06em;text-transform:uppercase}
.narration-model,.narration-standard{display:flex;flex-direction:column;gap:var(--space-3);padding:0 2px}
.narration-model .narration-menu-caption,.narration-standard .narration-menu-caption{padding-left:6px}
.narration-standard select{width:100%;height:44px;min-width:0;padding:0 8px;font:var(--size-label) var(--head);text-overflow:ellipsis}
.narration-model select{width:100%;height:44px;min-width:0;padding:0 8px;border:1px solid var(--nsfw-650);border-radius:var(--radius-md);background:var(--nsfw-900);color:var(--nsfw-200);font:var(--size-label) var(--head);text-overflow:ellipsis}
.narration-menu #narrator-style-button{min-height:44px;padding:8px 12px;border-radius:var(--radius-lg);text-align:left;font:600 var(--size-label) var(--head)}
.narration-status{grid-column:1/-1;display:flex;align-items:center;gap:var(--space-4);color:var(--muted);font:var(--size-caption)/1.4 var(--head)}
.composer .narration-status button{flex-shrink:0;min-width:44px;height:44px;padding:0 5px;border:0;border-radius:var(--radius-sm);background:none;color:var(--accent);font:var(--size-caption) var(--head);text-decoration:underline}
.composer [hidden]{display:none!important}
.composer[data-nsfw=true] .tools-adult{display:block}
.composer[data-nsfw=true] .tools-tabs [data-tool=narrator]{border-color:var(--nsfw-650);background:var(--nsfw-950);color:var(--nsfw-200)}
.composer[data-nsfw=true] .tools-tabs [data-tool=narrator][aria-selected=true]{border-color:var(--nsfw-300);background:var(--nsfw-300);color:var(--nsfw-950)}
.composer[data-nsfw=true] .narration-toggle{color:var(--nsfw-200)}
.composer[data-nsfw=true] .narration-track{background:var(--nsfw-600);border-color:var(--nsfw-400)}
.composer[data-nsfw=true] .narration-track span{background:var(--nsfw-50);transform:translateX(12px)}
.composer[data-nsfw=true] .narration-status{color:var(--nsfw-300)}
.tools-button:focus-visible,.tools-tabs button:focus-visible,.composer .narration-toggle:focus-visible,.narration-model select:focus-visible,.narration-standard select:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.composer button:disabled,.narration-model select:disabled,.narration-standard select:disabled{opacity:.5;cursor:default}
@media(prefers-reduced-motion:reduce){.narration-track span{transition:none}}
.primary .material-symbols-outlined{text-transform:none}
.mobile-nav button{min-width:0;overflow:hidden}
.dialog-card footer,.sync-actions{flex-wrap:wrap}
@media(max-width:800px){
  :root{--mobile-topbar:calc(61px + env(safe-area-inset-top));--mobile-nav:calc(52px + env(safe-area-inset-bottom))}
  html,body,#app{height:100dvh;max-height:100dvh;overflow:hidden}
  .topbar{height:var(--mobile-topbar);padding:calc(7px + env(safe-area-inset-top)) max(12px,env(safe-area-inset-right)) 7px max(12px,env(safe-area-inset-left))}
  .app-layout{height:calc(100dvh - var(--mobile-topbar) - var(--mobile-nav))}
  .story-column,.drawer{max-width:100%;min-height:0}
  .drawer{padding-left:env(safe-area-inset-left)}
  .chat,.panel-content,.inventory-content{overscroll-behavior:contain;-webkit-overflow-scrolling:touch}
  .composer{--composer-pad:max(12px,env(safe-area-inset-left));padding:10px max(12px,env(safe-area-inset-right)) 10px var(--composer-pad);gap:var(--space-5)}
  .mobile-nav{height:var(--mobile-nav)}
  .mobile-nav button{touch-action:manipulation}
}
@media(max-width:480px){
  .topbar{gap:var(--space-3);padding-left:max(9px,env(safe-area-inset-left));padding-right:max(9px,env(safe-area-inset-right))}
  .campaign-title{padding-inline:2px}
  .campaign-title b{font-size:var(--size-compact)}
  .top-actions{gap:var(--space-2)}
  .top-actions button{width:42px;height:42px;padding:0}
  .chat{padding:18px 15px}
  .message{line-height:1.55}
  .composer{--composer-pad:max(10px,env(safe-area-inset-left));padding:9px max(10px,env(safe-area-inset-right)) 9px var(--composer-pad);gap:var(--space-4)}
  .panel-content,.inventory-content{padding:10px}
  .status-card,.inventory-card,.lore-card{padding:14px;border-radius:var(--radius-xl)}
  .subtabs button{min-width:0;padding:12px 3px;font-size:var(--size-caption);overflow:hidden;text-overflow:ellipsis}
  dialog{max-width:calc(100vw - 20px)}
  .dialog-card{width:calc(100vw - 20px);min-width:0;max-width:none;padding:16px}
  .toast{max-width:calc(100vw - 28px);text-align:center}
}
@media(max-width:360px){
  .campaign-title small{display:none}
  .top-actions button{width:40px;height:40px}
}
@media(min-width:1200px){
  .chat{padding-inline:max(42px,7vw)}
  .message{max-width:900px}
  .panel-content,.inventory-content{padding:22px}
}

/* Persistent storage warning banner: unlike .toast it is always visible and
   interactive while shown, and stays until the storage condition is resolved. */
.storage-banner{position:fixed;top:max(12px,env(safe-area-inset-top));left:50%;transform:translateX(-50%);max-width:min(92vw,40rem);z-index:60;display:flex;gap:var(--space-5);align-items:center;flex-wrap:wrap;background:var(--danger-900);border:1px solid var(--danger-strong);border-radius:var(--radius-lg);padding:10px 14px;opacity:1;pointer-events:auto}
.storage-banner[hidden]{display:none}
.storage-banner button{padding:.35rem .7rem}
.cloud-status{padding:12px 15px;border:1px solid var(--accent-600);border-radius:var(--radius-lg);max-width:820px;margin:12px auto}
.cloud-status[hidden]{display:none}
.cloud-status p{margin:0 0 8px}
.cloud-status .sync-actions{margin-bottom:8px}
[data-sync-button]{position:relative}
[data-sync-button][data-cloud]::after{content:"";position:absolute;top:4px;right:4px;width:8px;height:8px;border-radius:var(--radius-round);background:var(--ok);box-shadow:0 0 0 2px var(--bg)}
[data-sync-button][data-cloud=saving]::after{background:var(--saving)}
[data-sync-button][data-cloud=problem]::after{background:var(--danger)}
.cloud-mark{display:inline-block;width:9px;height:9px;border-radius:var(--radius-round);background:var(--ok);vertical-align:middle}
.cloud-mark[data-state=saving]{background:var(--saving)}
.cloud-mark[data-state=problem],.cloud-mark[data-state=conflict],.cloud-mark[data-state=missing]{background:var(--danger)}
.cloud-mark[data-state=local]{background:transparent;border:1px solid var(--muted)}
.cloud-mark-label{white-space:nowrap}
.cloud-line{display:flex;gap:var(--space-5);align-items:flex-start;padding:5px 0}
.cloud-line .cloud-mark{flex:none;margin-top:.5em}
.cloud-remote{display:flex;gap:var(--space-5);align-items:center;justify-content:space-between;flex-wrap:wrap;padding:4px 0}

/* Notice chat entries: persisted failure/refusal records rendered inline in
   the transcript with the same label pattern as You/Voice messages. */
.message.notice{font-size:.85rem;color:var(--muted);border-left:2px solid var(--accent-600);padding-left:12px}
.message.notice:before{content:"Notice";display:block;font:var(--size-caption) var(--head);text-transform:uppercase;color:var(--accent-550)}
.message.notice.error{border-left-color:var(--danger)}
.message.notice.error:before{color:var(--danger)}

/* Magic: the improvised-working naming bar above the composer (v5 naming
   prompt) and the info notice kind, the Record note of magic and quest
   milestones in turns saved before v7.4 (the turn summary has them since). */
.working-bar{border-top:1px solid var(--line);background:var(--surface-warm);padding:10px max(15px,4vw);display:grid;gap:var(--space-4);max-height:36vh;overflow-y:auto;overscroll-behavior:contain}
.working-bar p{margin:0;font-size:.9rem;color:var(--text-warm);line-height:1.45}
.working-bar b{display:block;color:var(--accent);font:600 var(--size-caption) var(--head);text-transform:uppercase;letter-spacing:.08em;margin-bottom:2px}
.working-actions{display:flex;flex-wrap:wrap;gap:var(--space-4);align-items:center}.working-offer{display:grid;gap:var(--space-3)}.working-offer+.working-offer{padding-top:var(--space-4);border-top:1px solid var(--line)}
.working-actions input{flex:1 1 200px;min-width:0;border:1px solid var(--stone-750);border-radius:var(--radius-md);background:var(--field);padding:8px 10px;color:var(--text)}
.working-actions button{padding:.45rem .8rem;font-size:var(--size-small)}
.message.notice.info{border-left-color:var(--accent);color:var(--text-lore)}
.message.notice.info:before{content:"Record";color:var(--accent)}
@media(max-width:800px){.working-bar{padding:8px 10px}}

/* Retry (v5 ↻): a low-key control under the newest Voice entry that rolls the
   campaign back to before that turn and regenerates it from the same action. */
.action-glyph{display:block;width:16px;height:16px;flex:0 0 auto}
.message-tools{display:flex;align-items:center;flex-wrap:wrap;gap:var(--space-4);margin-top:8px}
.message-tools button{display:inline-flex;align-items:center;justify-content:center;gap:var(--space-3);min-width:36px;min-height:36px;padding:8px;border-radius:var(--radius-md);background:none;font:500 var(--size-caption) var(--head);letter-spacing:.04em;color:var(--muted)}
.message-tools button:hover,.message-tools button:focus-visible{color:var(--accent)}
.message-tools button:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.message-tools button:disabled{opacity:.45;cursor:not-allowed;color:var(--muted);border-color:var(--line)}
@media(max-width:800px),(pointer:coarse){.message-tools button{min-width:44px;min-height:44px}}
/* Topbar avatar (v6.11): the character's stored portrait beside the campaign
   name; hidden until a portrait exists. Text keeps its ellipsis rule. */
.campaign-title{display:flex;align-items:center;gap:var(--space-5)}
/* Over the title: where and when the story stands (or the profile's name). */
#campaign-note{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-transform:none;letter-spacing:.01em}
.campaign-title-text{min-width:0;flex:1 1 auto}
.campaign-avatar{width:34px;height:34px;border-radius:var(--radius-round);object-fit:cover;border:1px solid var(--accent-600);background:var(--well);flex:0 0 auto}
.campaign-avatar[hidden]{display:none}
/* Paint-portrait dialog (v6.11): style presets, a custom style line, and the
   editable prompt the painter will receive. */
.portrait-card{width:min(640px,94vw)}
.portrait-card textarea{font:var(--size-compact)/1.4 var(--body);resize:vertical}
.portrait-card label small{color:var(--muted);font-size:var(--size-ui)}
.portrait-card label[hidden]{display:none}
.portrait-card fieldset[hidden]{display:none}
.portrait-card .toggle-row.mode-unavailable{opacity:.5;cursor:not-allowed}
#scene-form .hint{margin:0;line-height:1.35}
.scene-camera-style{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-6)}
.scene-camera-style label,.scene-camera-style select{min-width:0;width:100%}
.scene-prepare-actions{display:flex;gap:var(--space-5);flex-wrap:wrap}
.scene-prepare-actions [hidden]{display:none}
#scene-prompt-count{display:block;text-align:right}
#scene-prompt-status{min-height:1.4em}
.painting-mode{margin:0;padding:0;border:0;min-width:0}
.painting-mode legend{margin-bottom:8px;color:var(--muted);font:var(--size-label) var(--head)}
.painting-mode-options{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-4)}
.painting-mode-options label{position:relative;margin:0;cursor:pointer}
.painting-mode-options input{position:absolute;opacity:0;width:1px;height:1px;min-height:0;padding:0}
.painting-mode-options span{display:flex;justify-content:center;align-items:center;min-height:44px;border:1px solid var(--line);border-radius:var(--radius-md);font:var(--size-label) var(--head);padding:10px}
.painting-mode-options input:checked+span{border-color:var(--accent-600);background:var(--accent-900);color:var(--accent-100)}
.painting-mode-options input:focus-visible+span{outline:2px solid var(--accent);outline-offset:2px}
.painting-mode-options .mode-unavailable{opacity:.5;cursor:not-allowed}
.painting-mode-note{margin:0;font-size:var(--size-ui)}
/* Scene images (v6.12): a wide illustration under a Voice entry, painted on
   request from that narration. The figure reserves its 16:9 box before the
   image decodes, so a rebuild never shifts the reader's place; the same box
   pulses as a placeholder while the painter works. Tap opens the viewer. */
.scene-image{margin:12px 0 2px;border:1px solid var(--line);border-radius:var(--radius-xl);overflow:hidden;background:var(--well);aspect-ratio:16/9}
.scene-image img{display:block;width:100%;height:100%;object-fit:cover;cursor:zoom-in}
.scene-image.placeholder{background:linear-gradient(135deg,var(--surface-warm-high),var(--well))}
.scene-image.busy{border-color:var(--accent);animation:portrait-pulse 1.4s ease-in-out infinite}
.scene-image.busy img{opacity:.55}
dialog.scene-viewer{max-width:96vw;max-height:96vh;position:relative}
.scene-viewer img{display:block;max-width:96vw;max-height:92vh;border:1px solid var(--accent-600);border-radius:var(--radius-lg);background:var(--well)}
.scene-viewer .viewer-close{position:absolute;top:2px;right:6px;color:var(--white);text-shadow:0 0 8px var(--black)}
.scene-viewer .viewer-download{position:absolute;right:10px;bottom:12px;min-height:40px;padding:0 16px;border-color:var(--accent-600);background:rgb(var(--bg-rgb) / .78);color:var(--accent);backdrop-filter:blur(6px);font:var(--size-label) var(--head)}
@media(prefers-reduced-motion:reduce){.scene-image.busy{animation:none}}

/* Turn in progress (v6.34): the chat bar keeps its one row. The ring takes the
   tools button's place (a spinner while the narrator writes, then one arc per record),
   the action box shows the stage and timer, and Stop takes Send's place. The
   ring opens the records list above the bar; the timer is quiet for screen
   readers. */
.composer[data-turn] #tools-button,.composer[data-turn] #action,.composer[data-turn] #send{display:none}
.composer:not([data-turn]) .turn-control{display:none}
.turn-ring{grid-column:1;display:grid;place-items:center;width:44px;height:48px;padding:0;border-color:var(--accent-600);border-radius:var(--radius-xl);background:var(--surface-warm)}
.turn-ring[aria-expanded=true]{border-color:var(--accent);background:var(--accent-950)}
.turn-ring:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.turn-ring-graphic{position:relative;display:grid;place-items:center;width:34px;height:34px}
.turn-ring-graphic svg{position:absolute;inset:0;width:100%;height:100%;overflow:visible}
.turn-ring-graphic circle,.turn-ring-graphic path{fill:none;stroke-width:3.2}
.turn-ring-count{position:relative;font:600 var(--size-micro) var(--head);color:var(--accent);font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.turn-ring-count .material-symbols-outlined{display:block;font-size:15px;color:var(--accent-600)}
.turn-ring-track,.turn-ring-arc[data-state=waiting]{stroke:var(--stone-800)}
.turn-ring-spin{stroke:var(--accent);stroke-linecap:round;transform-box:fill-box;transform-origin:center;animation:turn-spin 1.1s linear infinite}
.turn-ring-arc[data-state=running]{stroke:var(--accent-700);animation:turn-breathe 1.6s ease-in-out infinite}
.turn-ring-arc[data-state=retrying]{stroke:var(--warn);animation:turn-breathe .9s ease-in-out infinite}
.turn-ring-arc[data-state=done]{stroke:var(--accent)}
.turn-ring-arc[data-state=failed]{stroke:var(--danger)}
.turn-ring-graphic.is-retrying .turn-ring-spin{stroke:var(--warn)}
.turn-ring-graphic.is-saving svg{animation:turn-breathe 1.2s ease-in-out infinite}
.turn-ring-graphic.is-stopping .turn-ring-spin,.turn-ring-graphic.is-stopping .turn-ring-arc{stroke:var(--disabled);animation:none}
.turn-ring-graphic.is-stopping .turn-ring-count,.turn-ring-graphic.is-stopping .material-symbols-outlined{color:var(--disabled)}
.turn-status{grid-column:2;display:flex;align-items:center;justify-content:space-between;gap:var(--space-5);min-width:0;height:48px;padding:0 14px;border:1px solid var(--stone-800);border-radius:var(--radius-xl);background:var(--field)}
.turn-status [data-turn-stage]{min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font:500 var(--size-ui) var(--head);color:var(--accent)}
.turn-status [data-turn-elapsed]{flex:none;font:var(--size-label) var(--head);color:var(--muted);font-variant-numeric:tabular-nums}
.turn-stop-glyph{display:block;width:14px;height:14px;border-radius:var(--radius-xs);background:currentColor}
.turn-records{position:absolute;left:var(--composer-pad);bottom:calc(100% + 8px);z-index:6;width:min(320px,calc(100% - 2 * var(--composer-pad)));display:flex;flex-direction:column;gap:var(--space-4);padding:12px;background:var(--surface);border:1px solid var(--accent-600);border-radius:var(--radius-xl);box-shadow:var(--shadow-pop);font:var(--size-ui)/1.4 var(--head)}
.turn-records p{margin:0}
.turn-records-title{color:var(--accent)}
.turn-records-note{color:var(--muted);font-size:var(--size-label)}
.turn-records ul{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--space-3) var(--space-7);list-style:none;padding:0;margin:0;max-height:24vh;overflow:auto}
.turn-records li{display:flex;justify-content:space-between;gap:var(--space-4);min-width:0;font-size:var(--size-caption)}
.turn-records li span:last-child{color:var(--muted)}
.turn-records li[data-state=retrying] span:last-child{color:var(--warn)}
.turn-records li[data-state=failed] span:last-child{color:var(--danger)}
.turn-records li[data-state=done] span:last-child{color:var(--ok)}
.composer[data-nsfw=true] .turn-ring{border-color:var(--nsfw-400);background:var(--nsfw-900)}
.composer[data-nsfw=true] .turn-status{border-color:var(--nsfw-650)}
.composer[data-nsfw=true] .turn-stop{border-color:var(--nsfw-400);background:var(--nsfw-900);color:var(--nsfw-200)}
@keyframes turn-spin{to{transform:rotate(360deg)}}
@keyframes turn-breathe{50%{opacity:.4}}
@media(prefers-reduced-motion:reduce){.turn-ring-spin,.turn-ring-arc,.turn-ring-graphic svg{animation:none!important}}
/* Narration preview: visibly unsaved until the turn commits. */
.message.assistant.provisional:before{content:"Voice · not saved yet"}
.message.assistant.provisional p{opacity:.66}
#unfinished-turn{flex:0 0 auto;max-height:38vh;overflow:auto}
#unfinished-turn .unfinished-narration{white-space:pre-wrap;margin-top:8px}
/* Bottom bar on phones (v6.44): icons only; the open tab keeps its name, under
   an accent pill. Hidden names stay in the buttons for screen readers.
   styles/ledger.css now names every tab and fills the open one. */
@media(max-width:800px){
  .mobile-nav{padding:3px max(6px,env(safe-area-inset-right)) env(safe-area-inset-bottom) max(6px,env(safe-area-inset-left))}
  .mobile-nav button{display:grid;justify-items:center;align-content:center;gap:1px;padding:2px;font:600 0/1 var(--head)}
  .mobile-nav button.active{font-size:var(--size-tiny)}
  .mobile-nav button .material-symbols-outlined{display:grid;place-items:center;width:54px;height:30px;margin:0;border-radius:var(--radius-pill);font-size:22px}
  .mobile-nav button.active .material-symbols-outlined{background:var(--accent-900);color:var(--accent)}
}
/* Text for screen readers only. */
.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
/* No adventure open (src/app/story.mjs render; the page starts so): the welcome alone, without the records panel or the phone's tabs. */
#app.no-adventure{--mobile-nav:0px}
#app.no-adventure .drawer,#app.no-adventure .mobile-nav{display:none}
#app.no-adventure .app-layout{grid-template-columns:minmax(0,1fr)}
.skip-link{position:fixed;top:calc(8px + env(safe-area-inset-top));left:8px;z-index:1000;padding:10px 16px;border-radius:var(--radius-sm);background:var(--accent);color:var(--on-accent);font:600 var(--size-ui)/1.2 var(--head);text-decoration:none;transform:translateY(calc(-100% - 24px))}.skip-link:focus{transform:none;outline:2px solid var(--accent-100);outline-offset:2px}#app.no-adventure .skip-link{display:none}
