:root{--top-h:56px;--page-max:1760px;--gap:24px;--chat-w:400px;--room-top:calc(3 * var(--space));--radius:12px;--space:4px;--inset:16px;--icon-size:40px;--icon-small:32px;--glyph-size:20px;--icon-inset:calc((var(--icon-size) - var(--glyph-size))/2);--accent:#f03;--brand-me:#ffc83d;--brand-partner:#5b8cff;--char:#ffb35c;font-family:"Pretendard","Apple SD Gothic Neo","Malgun Gothic",system-ui,sans-serif}
/* Theme tokens. Dark is the default; light follows the system unless the viewer picked one ([data-theme] on <html>).
   Layers drawn over the video (controls, overlay/floating chat) always use the dark tokens so they stay readable on footage. */
:root,.controls,.chat.overlay,.chat.floating,.chat.typing,.stage-top{color-scheme:dark;--bg:#0f0f0f;--text:#f1f1f1;--text-2:#ccc;--muted:#aaa;--subtle:#888;--field:#121212;--field-shadow:inset 0 1px 2px rgba(0,0,0,.4);--panel:#272727;--button:#222;--line:#303030;--line-strong:#414141;--hover:#3f3f3f;--soft:rgba(255,255,255,.1);--soft-hover:rgba(255,255,255,.12);--inverse:#f1f1f1;--inverse-text:#0f0f0f;--inverse-hover:#d9d9d9;--dialog:#212121;--card:#181818;--scroll:#555;--focus-border:#717171;--focus-ring:rgba(255,255,255,.6);--backdrop:rgba(0,0,0,.7);--shadow:rgba(0,0,0,.6);--error-bg:#361c1c;--error-line:#653232;--error-text:#ffc5c5;--select-arrow:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23aaaaaa' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")}
:is(.controls,.chat.overlay,.chat.floating,.chat.typing,.stage-top){color:var(--text)}
@media(prefers-color-scheme:light){:root:not([data-theme=dark]){color-scheme:light;--bg:#fff;--text:#0f0f0f;--text-2:#3f3f3f;--muted:#606060;--subtle:#909090;--field:#fff;--field-shadow:inset 0 1px 2px #eee;--panel:#f2f2f2;--button:#f8f8f8;--line:#d3d3d3;--line-strong:#c6c6c6;--hover:#e5e5e5;--soft:rgba(0,0,0,.05);--soft-hover:rgba(0,0,0,.1);--inverse:#0f0f0f;--inverse-text:#fff;--inverse-hover:#272727;--dialog:#fff;--card:#f9f9f9;--scroll:#c1c1c1;--focus-border:#909090;--focus-ring:rgba(0,0,0,.55);--backdrop:rgba(0,0,0,.5);--shadow:rgba(0,0,0,.2);--error-bg:#fdecea;--error-line:#f5c2c0;--error-text:#b3261e;--select-arrow:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23606060' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")}}
:root[data-theme=light]{color-scheme:light;--bg:#fff;--text:#0f0f0f;--text-2:#3f3f3f;--muted:#606060;--subtle:#909090;--field:#fff;--field-shadow:inset 0 1px 2px #eee;--panel:#f2f2f2;--button:#f8f8f8;--line:#d3d3d3;--line-strong:#c6c6c6;--hover:#e5e5e5;--soft:rgba(0,0,0,.05);--soft-hover:rgba(0,0,0,.1);--inverse:#0f0f0f;--inverse-text:#fff;--inverse-hover:#272727;--dialog:#fff;--card:#f9f9f9;--scroll:#c1c1c1;--focus-border:#909090;--focus-ring:rgba(0,0,0,.55);--backdrop:rgba(0,0,0,.5);--shadow:rgba(0,0,0,.2);--error-bg:#fdecea;--error-line:#f5c2c0;--error-text:#b3261e;--select-arrow:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23606060' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")}
*{box-sizing:border-box;scrollbar-width:thin;scrollbar-color:var(--scroll) transparent}
*::-webkit-scrollbar{width:6px;height:6px}
*::-webkit-scrollbar-thumb{background:var(--scroll);border-radius:3px}
*::-webkit-scrollbar-track{background:transparent}
body{margin:0;background:var(--bg);color:var(--text);font-size:14px;line-height:1.55;overflow:hidden}
button,input,select,textarea{font:inherit;color:inherit}
button,summary,label.btn,label.pill-icon{cursor:pointer}
button{touch-action:manipulation}
button:disabled{cursor:default;opacity:.5}
:focus-visible{outline:2px solid var(--focus-ring);outline-offset:2px}
button:focus:not(:focus-visible){outline:none}
.dialog :is(input,select,textarea):focus{border-color:var(--focus-border)}
:is(.url-field,.compose) :is(input,textarea):is(:focus,:focus-visible){outline:none}
input,select,textarea{background:var(--field);border:1px solid var(--line);border-radius:8px;padding:calc(2.5 * var(--space)) calc(3 * var(--space));min-width:0}
input::placeholder,textarea::placeholder{color:var(--subtle)}
svg{display:block;flex-shrink:0}
#root{height:100dvh;display:flex;flex-direction:column;min-width:0}
.top{height:var(--top-h);flex-shrink:0;display:flex;align-items:center;gap:var(--gap);padding:0 var(--gap);padding-inline-end:calc(var(--gap) - var(--icon-inset));background:var(--bg)}
@font-face{font-family:"Fredoka";font-weight:300 700;font-display:swap;src:url(fredoka-covid.5e1c9ec7e4d2037d.woff2) format("woff2")}
.brand{width:180px;flex-shrink:0;display:flex;align-items:center;gap:calc(1.5 * var(--space));line-height:1}
/* Logo: a TV with the two viewers (me, partner) in front of it. The partner is cut out of "me" by a background-coloured edge. */
/* Like YouTube: the mark and the name are about the same height and share a centre line. */
.brand-mark{display:block;height:26px;width:auto;aspect-ratio:28/23;overflow:visible}
.brand-mark .me{fill:var(--brand-me)}
.brand-mark .partner{fill:var(--brand-partner);stroke:var(--bg);stroke-width:1.6}
.brand-name{font-family:"Fredoka",system-ui,sans-serif;font-size:29px;font-weight:530;letter-spacing:-.01em}
.url{display:flex;flex:1;min-width:0;max-width:620px;height:40px;margin:0 auto}
.url-field{display:flex;align-items:center;gap:calc(3 * var(--space));flex:1;min-width:0;padding-left:var(--inset);background:var(--field);border:1px solid var(--line);border-right:0;border-radius:40px 0 0 40px;box-shadow:var(--field-shadow)}
.url-icon{color:var(--muted);flex-shrink:0}
.url-field input{width:0;flex:1;min-width:0;border:0;border-radius:0;background:transparent;padding:calc(2 * var(--space)) calc(3 * var(--space)) calc(2 * var(--space)) 0;font-size:15px}
.url-field:focus-within{border-color:var(--focus-border)}
.url-go{display:grid;place-items:center;width:64px;flex-shrink:0;padding:0;border:1px solid var(--line);border-radius:0 40px 40px 0;background:var(--button);color:var(--text)}
.actions{display:flex;align-items:center;justify-content:flex-end;gap:calc(2 * var(--space));width:180px;flex-shrink:0}
.icon-btn,.pill-icon,.tab-btn{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:var(--icon-size);height:var(--icon-size);padding:0;border:0;border-radius:50%;background:transparent;transition:background .15s,color .15s}
.icon-btn:not(:disabled):hover{background:var(--soft-hover)}
.icon-btn:disabled{opacity:.5}
.pill-icon{background:var(--panel)}
.pill-icon:not(:disabled):not([aria-pressed=true]):hover,.tab-btn:not(:disabled):not(.active):hover,.url-go:not(:disabled):hover{background:var(--hover)}
.pill-icon[aria-pressed=true],.tab-btn.active{background:var(--inverse);color:var(--inverse-text)}
.spacer{flex:1;min-width:0}
.room{position:relative;display:grid;grid-template-columns:minmax(0,1fr) var(--chat-w);grid-template-areas:"watch chat" "below chat";grid-template-rows:max-content 1fr;gap:calc(3 * var(--space)) var(--gap);align-items:start;align-content:start;width:100%;max-width:var(--page-max);margin-inline:auto;padding:var(--gap);flex:1;min-height:0;overflow:auto;padding-top:var(--room-top)}
.watch{grid-area:watch;min-width:0}
/* The video box is isolated: nothing outside it (chat, text, progress) makes the browser lay out or repaint the video again. */
.stage{position:relative;overflow:hidden;width:100%;aspect-ratio:16/9;border-radius:var(--radius);background:#000;contain:layout paint;isolation:isolate}
.player{position:absolute;inset:0;background:#000}
.player>div,.player iframe{width:100%;height:100%;border:0}
.controls{position:absolute;inset:auto 0 0;z-index:2;background:rgba(0,0,0,.55);padding:0 calc(3 * var(--space)) var(--space);color:#fff}
.control-row{display:flex;align-items:center;gap:var(--space);height:48px}
.timecode{font-size:13px;color:#fff;font-variant-numeric:tabular-nums;white-space:nowrap;margin-left:8px}
#timeline{position:relative;display:flex;align-items:center;height:16px}
/* Progress bars only change transform (scaleX), like YouTube: no layout, no repaint. */
#timeline .bar{position:absolute;left:0;right:0;top:50%;height:3px;margin-top:-1.5px;transform-origin:0 50%;transform:scaleX(0);pointer-events:none;will-change:transform}
#timeline .bar.base{transform:none;background:rgba(255,255,255,.2)}
#timeline .bar.analyzed{background:rgba(255,255,255,.4)}
#timeline .bar.played{background:#f03}
#seek{position:relative;z-index:1;appearance:none;-webkit-appearance:none;display:block;width:100%;height:16px;padding:0;margin:0;border:0;border-radius:0;background:transparent;cursor:pointer}
#seek:disabled{cursor:default}
#seek::-webkit-slider-runnable-track{height:3px;border:0;background:transparent}
#seek::-moz-range-track{height:3px;border:0;background:transparent}
#seek::-webkit-slider-thumb{appearance:none;-webkit-appearance:none;width:12px;height:12px;margin-top:-4.5px;border:0;border-radius:50%;background:#f03;opacity:0;transition:opacity .12s}
#seek::-moz-range-thumb{width:12px;height:12px;border:0;border-radius:50%;background:#f03;opacity:0;transition:opacity .12s}
#seek:hover::-webkit-slider-thumb,#seek:focus-visible::-webkit-slider-thumb{opacity:1}
#seek:hover::-moz-range-thumb,#seek:focus-visible::-moz-range-thumb{opacity:1}
.below{grid-area:below;min-width:0;padding-bottom:0}
h1#title{font-size:20px;font-weight:700;line-height:1.45;margin:0 0 calc(3 * var(--space));overflow-wrap:anywhere}
.owner{display:flex;align-items:center;gap:calc(3 * var(--space));margin-bottom:var(--inset);min-width:0}
.avatar{display:inline-flex;align-items:center;justify-content:center;flex:0 0 24px;width:24px;height:24px;border-radius:50%;background:var(--char);color:#0f0f0f;font-size:12px;font-weight:600}
.avatar.big{width:40px;height:40px;flex-basis:40px;font-size:18px;background:var(--char)}
.owner-name{font-size:16px;font-weight:600;min-width:0;overflow-wrap:anywhere}
.tabs{display:flex;flex-wrap:wrap;gap:calc(2 * var(--space));margin:var(--inset) 0 calc(3 * var(--space))}
.tab-btn{width:44px;height:36px;border-radius:8px;background:var(--panel)}
#detail{font-size:13px;color:var(--text-2);overflow-wrap:anywhere}
.row{display:grid;grid-template-columns:48px minmax(0,1fr);gap:calc(3 * var(--space));padding:calc(3 * var(--space)) 0;border-top:1px solid var(--line);overflow-wrap:anywhere}
.row time{color:var(--muted);font-variant-numeric:tabular-nums}
#usage{font-size:12px;color:var(--muted)}
#captionRaw{width:100%;min-height:130px;resize:vertical}
.chat{grid-area:chat;position:sticky;top:0;display:flex;flex-direction:column;min-width:0;min-height:0;height:calc(100dvh - var(--top-h) - var(--room-top) - var(--gap));border:1px solid var(--line);border-radius:var(--radius);background:var(--bg);overflow:hidden}
.chat-header{display:flex;align-items:center;gap:calc(2.5 * var(--space));flex-shrink:0;height:44px;padding:0 var(--inset);padding-inline-end:calc(var(--inset) - var(--icon-inset));border-bottom:1px solid var(--line)}
.chat-title{display:flex;align-items:center;gap:calc(2 * var(--space));min-width:0}
.chat-title strong{font-size:14px;font-weight:600}
#chatResize,#chatGrip{display:none}
.messages{flex:1;min-height:0;min-width:0;overflow-x:hidden;overflow-y:auto;padding:8px 0}
/* As in a messenger the lines sit at the bottom and a new one pushes the others up (margin-top:auto keeps the list scrollable,
   unlike justify-content:flex-end) */
.messages{display:flex;flex-direction:column}
.messages>:first-child{margin-top:auto}
.messages.sliding{overflow-y:hidden}
.msg{display:flex;align-items:flex-start;gap:calc(2 * var(--space));min-width:0;max-width:100%;padding:calc(1.5 * var(--space)) var(--inset);font-size:14px;line-height:1.55;overflow-wrap:anywhere}
.msg .line{flex:1;min-width:0;max-width:100%;overflow-wrap:anywhere}
.msg time{font-size:12px;color:var(--muted);margin-right:calc(2 * var(--space));font-variant-numeric:tabular-nums}
.msg .name{font-weight:600;margin-right:calc(2 * var(--space));color:var(--char)}
.msg.user .avatar{background:#717171;color:#fff}
.msg.user .name{color:var(--muted)}
.msg .text{white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word}
.compose{flex-shrink:0;min-width:0;padding:calc(3 * var(--space))}
.compose form{display:flex;align-items:center;gap:calc(1.5 * var(--space));min-width:0;background:var(--panel);border:1px solid var(--line);border-radius:22px;padding:var(--space) calc(3 * var(--space) - (var(--icon-small) - var(--glyph-size))/2) var(--space) calc(3 * var(--space))}
.compose form:focus-within{border-color:var(--focus-border)}
.compose textarea:focus,.compose textarea:focus-visible{outline:none}
.compose textarea{width:0;flex:1;min-width:0;height:38px;min-height:38px;max-height:calc(5 * 22px + 4 * var(--space));resize:none;background:transparent;border:0;padding:calc(2 * var(--space)) 0;line-height:22px;font-size:14px;white-space:pre-wrap;overflow-wrap:anywhere;overflow-x:hidden}
.compose #send{width:var(--icon-small);height:var(--icon-small)}
/* Over-video chat is a separate layer in #room, never inside the video box. JS sets left/top at its bottom edge; translateY(-100%) lifts it. Drag uses `translate` only. */
.chat.overlay,.chat.floating{position:absolute;z-index:3;grid-area:auto;min-height:0;transform:translateY(-100%);will-change:transform;contain:layout paint}
.chat.overlay{background:rgba(15,15,15,.65);border:1px solid rgba(255,255,255,.08);border-radius:14px}
.chat.overlay .chat-header{height:44px;cursor:move;touch-action:none}
.chat.overlay #chatResize{display:block;position:absolute;inset:0 0 auto;height:10px;z-index:1;cursor:ns-resize;touch-action:none}
.chat.dragging{will-change:transform;user-select:none;transition:none}
.chat.floating{height:auto;background:transparent;border:0;border-radius:0}
.chat.floating .chat-header{display:none}
.chat.floating #chatGrip{display:flex;align-items:center;justify-content:center;align-self:center;width:28px;height:20px;flex-shrink:0;margin-bottom:calc(2 * var(--space));border-radius:10px;background:rgba(15,15,15,.45);cursor:move;touch-action:none}
.chat.floating .messages{display:flex;flex-direction:column;justify-content:flex-end;gap:calc(2 * var(--space));overflow:hidden;padding:0;min-width:0}
.chat.floating .msg{display:none;flex-shrink:0;align-self:flex-start;max-width:100%;background:rgba(15,15,15,.5);border-radius:16px;padding:7px 12px 7px 7px;transition:opacity .24s}
.chat.floating .msg:nth-last-child(-n+3){display:flex}
.chat.floating .msg:nth-last-child(3){opacity:.45}
.chat.floating .msg:nth-last-child(2){opacity:.8}
.chat.floating .msg time{display:none}
.chat.floating .compose{padding:8px 0 0}
/* No backdrop blur over the video: re-blurring a playing video every frame made playback stutter. Plain translucent black instead. */
.chat.floating .compose form{background:rgba(15,15,15,.5);border:1px solid rgba(255,255,255,.12);border-radius:22px}
.chat.floating .compose form:focus-within{border-color:var(--focus-border)}
.chat.typing{transform:none!important;translate:none!important;position:fixed;left:0!important;right:0!important;top:auto;bottom:var(--kb,0px)!important;width:auto!important;height:auto!important;max-height:calc(100dvh - var(--kb,0px));background:rgba(15,15,15,.9);border-radius:0;z-index:5}
.chat.typing .msg:not(:last-child){display:none}
.chat.typing .msg:last-child{display:flex;opacity:1}
.chat.typing #chatGrip,.chat.typing #chatResize{display:none}
.chat.typing .compose{padding:8px 12px}
.chat-hidden #chat{display:none!important}
.chat-hidden .room{grid-template-columns:minmax(0,1fr);grid-template-areas:"watch" "below"}
.theater .room{max-width:none;grid-template-columns:minmax(0,1fr);grid-template-areas:"watch" "below";padding:0;gap:0}
.theater .stage{height:min(56.25vw,calc(100dvh - var(--top-h) - 3 * var(--gap)));aspect-ratio:auto;border-radius:0}
.theater .below{padding:var(--inset) var(--gap)}
.vertical #theater{display:none}

/* Settings and shared form controls retained from the original stylesheet. */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:calc(2 * var(--space));border:0;border-radius:20px;background:var(--inverse);color:var(--inverse-text);padding:calc(2.25 * var(--space)) var(--inset);font-weight:600;font-size:13px;line-height:20px;white-space:nowrap;transition:background .15s,color .15s}
.btn:not(:disabled):hover{background:var(--inverse-hover)}
.btn.secondary{background:var(--panel);color:var(--text)}
.btn.secondary:not(:disabled):hover,.btn.ghost:not(:disabled):hover{background:var(--hover);color:var(--text)}
.btn.ghost{background:transparent;color:var(--text)}
.note{font-size:11px;color:var(--subtle);margin:calc(2 * var(--space)) calc(0.75 * var(--space)) 0;line-height:1.7}
.modal{position:fixed;inset:0;background:var(--backdrop);display:grid;place-items:center;padding:var(--gap);z-index:10}
.modal[hidden]{display:none}
.dialog{width:min(640px,100%);max-height:calc(100dvh - 2 * var(--gap));overflow:auto;background:var(--dialog);border:1px solid var(--line);border-radius:16px;padding:calc(7 * var(--space));box-shadow:0 24px 80px var(--shadow);scrollbar-width:thin}
.dialog h2{font-size:22px;margin:0 0 var(--space);letter-spacing:-.5px}
.dialog-nav{display:flex;gap:calc(2 * var(--space));border-bottom:1px solid var(--line);margin:calc(5.5 * var(--space)) 0 calc(4.5 * var(--space));padding-bottom:14px}
.dialog .btn{border-radius:8px}
.dialog-nav .btn{flex:1;padding:8px}
.dialog-nav .secondary{background:var(--inverse);color:var(--inverse-text)}
.connection{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);padding:var(--inset);margin:12px 0}
.connection>b{font-size:13px}
.field{display:grid;gap:calc(2 * var(--space));margin:12px 0}
.field:last-child{margin-bottom:0}
.field label{font-size:13px;color:var(--text-2)}
.field small{font-size:11px;color:var(--muted)}
.field input,.field select,.field textarea{width:100%;font-size:13px}
.grid{display:grid;grid-template-columns:1fr 1fr;gap:var(--inset)}
.switchline{display:flex;justify-content:space-between;align-items:center;gap:var(--inset);padding:calc(4.5 * var(--space)) 0;border-bottom:1px solid var(--line);font-size:13px}
.switchline input{accent-color:var(--accent);width:18px;height:18px}
#cooldown{accent-color:var(--accent);padding:0}
#persona{min-height:100px;resize:vertical}
.dialog-actions{display:flex;justify-content:space-between;gap:calc(3 * var(--space));margin-top:var(--gap);padding-top:calc(4.5 * var(--space));border-top:1px solid var(--line)}
.dialog-actions-end{display:flex;gap:calc(2 * var(--space))}
/* Error toasts: bottom centre, above everything, close by themselves */
.toasts{position:fixed;left:50%;bottom:calc(6 * var(--space));transform:translateX(-50%);z-index:100;display:flex;flex-direction:column;align-items:center;gap:calc(2 * var(--space));width:max-content;max-width:calc(100vw - 2 * var(--inset));pointer-events:none}
.toast{display:flex;align-items:center;gap:calc(2 * var(--space));max-width:520px;padding:calc(2 * var(--space)) calc(2 * var(--space)) calc(2 * var(--space)) var(--inset);border-radius:8px;background:var(--inverse);color:var(--inverse-text);font-size:13px;line-height:1.5;box-shadow:0 8px 24px var(--shadow);pointer-events:auto;animation:toast-in .18s ease-out}
.toast span{flex:1;min-width:0;overflow-wrap:anywhere}
.toast .icon-btn{width:var(--icon-small);height:var(--icon-small);color:inherit}
@keyframes toast-in{from{opacity:0;transform:translateY(8px)}}
:is(#settingsTitle,#noticeTitle):focus{outline:none}
.field-head{display:flex;align-items:center;justify-content:space-between;gap:calc(2 * var(--space))}
.field-head .btn{font-size:12px;padding:var(--space) calc(2.5 * var(--space));min-height:0}
.connection small{font-size:11px;color:var(--muted);margin-top:2px}

@media(min-width:761px){
body:not(.theater):not(.vertical) .stage{width:min(100%,calc((100dvh - var(--top-h) - var(--room-top) - var(--gap)) * 16 / 9))}
/* The header shares the page width with the content below, so the logo lines up with the video on wide screens. */
body:not(.theater):not(.vertical) .top{width:100%;max-width:var(--page-max);margin-inline:auto}
.vertical .room{grid-template-areas:"below watch chat";grid-template-columns:360px auto 400px;grid-template-rows:1fr;justify-content:center;max-width:none}
.vertical .stage{aspect-ratio:9/16;height:calc(100dvh - var(--top-h) - var(--room-top) - var(--gap));width:auto;border-radius:var(--radius)}
.vertical.chat-hidden .room{grid-template-areas:"below watch";grid-template-columns:360px auto}
/* Vertical video: the page stays put beside the video; a long list (captions, scenes) scrolls inside the tab instead. */
.vertical .room{overflow:hidden}
.vertical .below{align-self:stretch;display:flex;flex-direction:column;min-height:0}
.vertical #detail{flex:1;min-height:0;overflow-y:auto}
.vertical .below .tabs{margin-top:0}
/* Under a wide video the page still scrolls, but only so far: the tab's list (captions, scenes…) is at most one screen
   tall and scrolls on its own, so scrolling down just brings the tabs to the top with the list filling the rest. */
body:not(.vertical) #detail{max-height:calc(100dvh - var(--top-h) - 96px);overflow-y:auto}
}
@media(max-width:760px){
body{overflow:auto}
#root{height:auto;min-height:100dvh}
.top{gap:calc(2 * var(--space));padding:0 calc(var(--gap)/2);padding-inline-end:calc(var(--gap)/2 - var(--icon-inset))}
.brand{width:auto}
.brand-name{display:none}
.url{max-width:none;flex:1}
.url-field{gap:calc(2 * var(--space));padding-left:10px}
.url-go{width:40px}
.actions{width:auto;gap:0}
.room,.theater .room,.chat-hidden .room{grid-template-columns:minmax(0,1fr);grid-template-areas:"watch" "below" "chat";grid-template-rows:auto auto auto;padding:0;gap:0;overflow:visible}
.chat-hidden .room{grid-template-areas:"watch" "below";grid-template-rows:auto auto}
.stage{border-radius:0}
.below,.theater .below{padding:var(--inset) var(--gap)}
.room>.chat:not(.overlay):not(.floating){position:static;height:max(320px,calc(100svh - var(--top-h) - 56.25vw - 150px));border-radius:0;border-inline:0}
.vertical .stage{height:calc(100svh - var(--top-h));width:100%;aspect-ratio:auto;border-radius:0}
.control-row{gap:0}
.timecode{margin-left:4px}
.modal{padding:calc(3 * var(--space))}
.dialog{padding:calc(5 * var(--space));max-height:calc(100dvh - var(--gap))}
.dialog-nav{gap:4px;flex-wrap:wrap}
.dialog-nav .btn{font-size:12px;padding:8px 6px;flex:1 1 30%}
.grid{grid-template-columns:1fr}
}
@media(max-width:380px){
.connection{padding:calc(3 * var(--space))}
}
@media(max-height:500px) and (orientation:landscape){
.theater.has-video .stage{height:100dvh}
}
@media(pointer:coarse){
#seek::-webkit-slider-thumb{opacity:1}
#seek::-moz-range-thumb{opacity:1}
}
.hidden,[hidden]{display:none!important}
@media(prefers-reduced-motion:reduce){
*,*::before,*::after{animation:none!important;transition:none!important;scroll-behavior:auto!important}
}
@media(min-width:761px){.chat-hidden:not(.theater):not(.vertical) .room{grid-template-columns:minmax(0,calc(100% - var(--chat-w) - var(--gap)));justify-content:center}}
/* Photo avatars (character image / persona icon from Risu) fill the same circle as the initial. */
.avatar{overflow:hidden}
.avatar img{display:block;width:100%;height:100%;object-fit:cover}
/* Settings › 요청 로그 */
.log-head{display:flex;align-items:center;justify-content:space-between;gap:calc(2 * var(--space));margin-bottom:calc(2 * var(--space));font-size:13px;color:var(--muted)}
.log-row{border-top:1px solid var(--line)}
.log-row summary{display:flex;align-items:center;gap:calc(2 * var(--space));padding:calc(2.5 * var(--space)) 0;cursor:pointer;list-style:none;font-size:13px;min-width:0}
.log-row summary::-webkit-details-marker{display:none}
.log-status{flex:0 0 auto;min-width:36px;padding:1px 6px;border-radius:6px;text-align:center;font-weight:600;font-size:12px;font-variant-numeric:tabular-nums;background:var(--panel)}
.log-status.ok{color:#1e9e5a}
.log-status.bad{color:var(--accent)}
.log-status.wait{color:var(--muted)}
.log-time,.log-ms{flex:0 0 auto;color:var(--muted);font-variant-numeric:tabular-nums}
.log-method{flex:0 0 auto;font-weight:600;font-size:12px}
.log-url{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.log-url b{font-weight:600;margin-right:2px}
.log-body{padding:0 0 calc(3 * var(--space));font-size:12px}
.log-body b{display:block;margin:calc(2 * var(--space)) 0 var(--space);font-size:12px}
.log-full{color:var(--muted);overflow-wrap:anywhere}
/* Volume: the slider opens next to the speaker on hover, like YouTube */
.volume{display:flex;align-items:center}
.volume-range{-webkit-appearance:none;appearance:none;width:0;height:36px;margin:0;padding:0;border:0;border-radius:0;background:transparent;opacity:0;cursor:pointer;transition:width .2s cubic-bezier(.4,0,1,1),margin .2s cubic-bezier(.4,0,1,1),opacity .2s}
.volume:is(:hover,:focus-within) .volume-range{width:64px;margin-right:3px;opacity:1;transition-timing-function:cubic-bezier(0,0,.2,1)}
.volume-range::-webkit-slider-runnable-track{height:3px;background:linear-gradient(to right,#fff var(--fill,100%),rgba(255,255,255,.2) var(--fill,100%))}
.volume-range::-webkit-slider-thumb{-webkit-appearance:none;width:12px;height:12px;margin-top:-4.5px;border:0;border-radius:50%;background:#fff}
.volume-range::-moz-range-track{height:3px;background:rgba(255,255,255,.2)}
.volume-range::-moz-range-progress{height:3px;background:#fff}
.volume-range::-moz-range-thumb{width:12px;height:12px;border:0;border-radius:50%;background:#fff}
/* Markdown-ish text: headings, tags and body in different colours */
.md{line-height:1.7;color:var(--text-2)}
.md-h{color:var(--text);font-weight:700;margin:calc(2 * var(--space)) 0 var(--space)}
.md-h:first-child{margin-top:0}
.md-h1{font-size:1.2em}
.md-h2{font-size:1.08em;color:var(--brand-partner)}
.md-h3{color:var(--char)}
.md-gap{height:calc(2 * var(--space))}
.md-li{display:flex;gap:calc(2 * var(--space))}
.md-li.nested{padding-left:var(--inset)}
.md-bullet{flex:0 0 auto;color:var(--muted)}
.md strong{color:var(--text)}
.md code{padding:0 4px;border-radius:4px;background:var(--soft);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.92em}
.tag-br{color:var(--muted)}
.tag-name{color:var(--brand-partner);font-weight:600}
.md :is(.tag-br,.tag-name){font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.92em}
/* Prompt editors: transparent textarea over a coloured copy of its text */
.hl-edit{display:grid;min-width:0}
.hl-edit>*{grid-area:1/1;min-width:0}
.hl-layer{background:var(--field);border-radius:8px;padding:calc(2.5 * var(--space)) calc(3 * var(--space));border:1px solid transparent;font-size:13px;white-space:pre-wrap;overflow-wrap:anywhere;color:var(--text);pointer-events:none}
.hl-edit textarea{position:relative;color:transparent;caret-color:var(--text);background:transparent}
.hl-edit textarea::selection{background:var(--soft-hover)}
.story-seg{padding:calc(3 * var(--space)) 0;border-top:1px solid var(--line)}
.story-seg:first-child{border-top:0;padding-top:0}
.story-seg time{display:block;margin-bottom:var(--space);color:var(--muted);font-variant-numeric:tabular-nums}
.log-view{max-height:420px;overflow:auto;padding:calc(2 * var(--space)) calc(3 * var(--space));border-radius:8px;background:var(--card);border:1px solid var(--line);overflow-wrap:anywhere;font-size:12px}
.json-obj{display:flex;flex-direction:column;gap:2px}
.json-row{display:flex;gap:calc(2 * var(--space));min-width:0}
.json-row.block{flex-direction:column;gap:2px}
.json-row.block>:is(.json-obj,.md){padding-left:calc(3 * var(--space));border-left:2px solid var(--line)}
.json-k{flex:0 0 auto;color:var(--muted);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
.json-s{color:var(--text)}
.json-n{color:var(--brand-partner);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
.log-body pre{margin:0;max-height:240px;overflow:auto;padding:calc(2 * var(--space)) calc(3 * var(--space));border-radius:8px;background:var(--card);border:1px solid var(--line);white-space:pre-wrap;overflow-wrap:anywhere;font:12px/1.5 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
/* Settings › 모델 연결: connection cards with their model list */
.conn-head{display:flex;align-items:center;gap:calc(2 * var(--space));margin-bottom:calc(2 * var(--space))}
.conn-name{flex:1;min-width:0;font-weight:600;font-size:14px;background:transparent;border-color:transparent;padding-inline:calc(2 * var(--space))}
.conn-name:hover,.conn-name:focus{border-color:var(--line)}
.conn-head .icon-btn{width:var(--icon-small);height:var(--icon-small);color:var(--muted)}
.model-chips{display:flex;flex-wrap:wrap;gap:calc(1.5 * var(--space))}
.chip{display:inline-flex;align-items:center;gap:var(--space);max-width:100%;padding:2px 4px 2px 10px;border-radius:14px;background:var(--panel);font-size:12px;overflow-wrap:anywhere}
.chip button{display:grid;place-items:center;width:20px;height:20px;padding:0;border:0;border-radius:50%;background:transparent;color:var(--muted);font-size:14px;line-height:1}
.chip button:hover{background:var(--hover);color:var(--text)}
.model-add{display:flex;gap:calc(2 * var(--space));min-width:0}
.model-add>input,.model-add>select{flex:1;min-width:0}
.model-add .btn{flex-shrink:0;border-radius:8px;font-size:12px}
#addConnection{border-radius:8px;gap:var(--space)}
.field [hidden]{display:none!important}
.grid{align-items:start}
/* 모델 연결 › click a model to open its settings */
.chip-label{display:block;min-width:0;padding:0;border:0;background:transparent;color:inherit;font:inherit;cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;text-align:left}
.chip.open{background:var(--inverse);color:var(--inverse-text)}
.chip.open button{color:inherit}
.model-edit{display:grid;gap:calc(1.5 * var(--space));padding:calc(3 * var(--space));border:1px solid var(--line);border-radius:8px}
.model-edit b{font-size:13px;overflow-wrap:anywhere}
.model-edit label{display:flex;align-items:center;gap:calc(2 * var(--space));font-size:13px}
.model-edit input{width:140px}
.model-edit small{color:var(--muted);font-size:11px}
.chip .chip-label{width:auto;height:auto;border-radius:0;font-size:12px;line-height:1.5;color:inherit;display:block}
.chip .chip-label:hover{background:transparent;text-decoration:underline}
.model-add>input.tokens{flex:0 0 184px}
.model-add{flex-wrap:wrap}
.model-add>input:not(.tokens),.model-add>select{flex:1 1 160px}
/* Form controls: one height for text fields and dropdowns; dropdowns get the app's own chevron instead of the browser arrow. */
input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=file]),select{min-height:40px;line-height:20px}
select{appearance:none;-webkit-appearance:none;padding-right:36px;background-image:var(--select-arrow);background-repeat:no-repeat;background-position:right 12px center;background-size:16px;cursor:pointer;text-overflow:ellipsis}
select:disabled{cursor:default;opacity:.6}
.grid{row-gap:calc(3 * var(--space))}
.grid>.field{margin:0}
/* ? help: a small round button beside a label; opens a short bullet list */
.label-help{display:inline-flex;align-items:center;gap:calc(1.5 * var(--space));min-width:0}
.label-help b{font-size:14px}
.help-btn{display:inline-grid;place-items:center;flex-shrink:0;width:18px;height:18px;padding:0;border:1px solid var(--line);border-radius:50%;background:transparent;color:var(--muted);font-size:11px;font-weight:700;line-height:1}
.help-btn:hover,.help-btn[aria-expanded=true]{background:var(--panel);color:var(--text)}
.help code{font:11px/1.4 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;padding:0 3px;border-radius:4px;background:var(--panel);color:var(--text)}
.conn-foot{display:flex;align-items:center;gap:calc(2 * var(--space))}
.adv-grid{margin-top:calc(4 * var(--space))}
.help{display:grid;grid-template-columns:max-content 1fr;gap:calc(1.5 * var(--space)) calc(3 * var(--space));margin:0;padding:calc(2.5 * var(--space)) calc(3 * var(--space));border-radius:8px;background:var(--card);border:1px solid var(--line);font-size:12px;line-height:1.5}
.help[hidden]{display:none}
.help dt{color:var(--text);font-weight:600;white-space:nowrap}
.help dd{margin:0;color:var(--text-2);min-width:0;overflow-wrap:anywhere}
/* 프롬프트 탭: each prompt folds, closed by default */
.prompt-item{border-top:1px solid var(--line)}
.prompt-item textarea{width:100%;font-size:13px;resize:vertical}
.prompt-item+.btn{margin-top:calc(4 * var(--space))}
.help dt{white-space:normal}
.help{grid-template-columns:minmax(max-content,auto) 1fr}
/* Settings dialog: one fixed height for every tab; title, tabs and the save row stay put, only the content scrolls. */
.dialog{display:flex;flex-direction:column;height:min(880px,calc(100dvh - 2 * var(--gap)));max-height:none;overflow:hidden}
.dialog>h2,.dialog>.dialog-nav,.dialog>.dialog-actions{flex-shrink:0}
#settingsBody{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;scrollbar-gutter:stable;margin-right:calc(-3 * var(--space));padding-right:calc(3 * var(--space))}
.dialog-actions{margin-top:calc(3 * var(--space))}
/* Prompt editors grow with their text, so there is only one scroll (the dialog's). */
.prompt-item textarea{field-sizing:content;min-height:120px;max-height:none;overflow:hidden}
.prompt-item #persona{min-height:80px}
@media(max-width:760px){.dialog{height:calc(100dvh - var(--gap))}}
/* 프롬프트 탭 layout: header row (fold · ? · 기본값으로), then its help, then the editor */
.prompts-head{display:flex;align-items:center;padding-bottom:calc(3 * var(--space))}
.prompt-head{display:flex;align-items:center;gap:calc(1.5 * var(--space));min-height:48px}
.prompt-toggle{display:inline-flex;align-items:center;gap:calc(1.5 * var(--space));padding:0;border:0;background:transparent;color:var(--text);font:inherit;font-size:14px;font-weight:600;cursor:pointer}
.prompt-toggle .fold{display:inline-grid;color:var(--muted);transition:transform .15s}
.prompt-toggle[aria-expanded=true] .fold{transform:rotate(90deg)}
.prompt-item>.help{margin-bottom:calc(3 * var(--space))}
.prompt-body{padding-bottom:calc(3 * var(--space))}
/* 분석 결과 */
.results-head{display:flex;align-items:center;justify-content:space-between;gap:calc(2 * var(--space));flex-wrap:wrap;font-size:13px;color:var(--muted)}
.results-note{margin:calc(2 * var(--space)) 0 0;font-size:12px;color:var(--muted)}
#promptResults h4{margin:calc(5 * var(--space)) 0 calc(2 * var(--space));font-size:13px}
.results-empty{margin:0;font-size:12px;color:var(--muted)}
.result-text{white-space:pre-wrap;overflow-wrap:anywhere;font-size:13px;line-height:1.7;color:var(--text-2)}
.result-seg{border-top:1px solid var(--line);padding:calc(2 * var(--space)) 0}
.result-seg summary{cursor:pointer;font-size:13px;font-variant-numeric:tabular-nums}
.result-seg[open] summary{margin-bottom:calc(2 * var(--space))}
.result-events{margin:calc(2 * var(--space)) 0 0;padding:0;list-style:none;display:grid;gap:calc(1.5 * var(--space));font-size:12px;color:var(--text-2)}
.result-events time{display:inline-block;min-width:44px;margin-right:calc(2 * var(--space));color:var(--muted);font-variant-numeric:tabular-nums}
.result-state{margin-left:var(--space);font-size:11px;color:var(--muted)}
/* In-app confirmation over the settings dialog */
.dialog{position:relative}
.confirm-layer{position:absolute;inset:0;z-index:5;display:grid;place-items:center;padding:var(--gap);background:var(--backdrop);border-radius:inherit}
.confirm-box{width:min(360px,100%);padding:calc(5 * var(--space));border-radius:var(--radius);background:var(--dialog);border:1px solid var(--line);box-shadow:0 16px 48px var(--shadow)}
.confirm-box p{margin:0 0 calc(5 * var(--space));font-size:14px;line-height:1.6;overflow-wrap:anywhere}
.confirm-actions{display:flex;justify-content:flex-end;gap:calc(2 * var(--space))}
.btn.danger{background:var(--accent);color:#fff}
.btn.danger:not(:disabled):hover{background:#d4002b}
.hl-layer .tag-name{font-weight:inherit}

/* Loading screen (in index.html, replaced when the app starts) */
.boot-screen{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:calc(5 * var(--space))}
.boot-brand{display:flex;align-items:center;gap:calc(2 * var(--space));animation:boot-pulse 1.4s ease-in-out infinite}
.boot-brand .brand-mark{height:40px}
.boot-brand .brand-name{display:block;font-size:44px}
.boot-bar{width:120px;height:3px;border-radius:2px;background:var(--soft-hover);overflow:hidden}
.boot-bar::after{content:"";display:block;width:40%;height:100%;border-radius:inherit;background:var(--text);animation:boot-slide 1.1s ease-in-out infinite}
@keyframes boot-pulse{50%{opacity:.7}}
@keyframes boot-slide{from{transform:translateX(-100%)}to{transform:translateX(250%)}}
/* Notices: bell with a red dot for unchecked notices, and a floating list under it */
.notice-wrap{position:relative}
.notice-dot{position:absolute;top:8px;right:9px;width:8px;height:8px;border-radius:50%;background:var(--accent);box-shadow:0 0 0 2px var(--bg)}
.notice-pop{position:absolute;top:calc(100% + var(--space));right:0;z-index:20;width:320px;max-width:calc(100vw - 2 * var(--inset));padding:calc(2 * var(--space));border-radius:var(--radius);background:var(--dialog);border:1px solid var(--line);box-shadow:0 12px 40px var(--shadow)}
.notice-head{padding:calc(1.5 * var(--space)) calc(2 * var(--space)) calc(2 * var(--space));font-weight:600}
.notice-item{display:flex;align-items:center;gap:calc(2 * var(--space));padding:calc(1.5 * var(--space)) calc(2 * var(--space));border-radius:8px}
.notice-item:hover{background:var(--soft)}
.notice-item label{flex:1;min-width:0;display:flex;align-items:center;gap:calc(2 * var(--space));cursor:pointer}
.notice-item input{width:16px;height:16px;margin:0;padding:0;accent-color:var(--accent)}
.notice-item .btn{padding:calc(1.5 * var(--space)) calc(3 * var(--space));font-size:13px}
.dialog.notice-dialog{width:min(460px,100%);height:auto;max-height:calc(100dvh - 2 * var(--gap))}
.notice-steps{margin:var(--inset) 0 0;padding-left:calc(5 * var(--space));display:flex;flex-direction:column;gap:calc(3 * var(--space));line-height:1.6}
a.btn{text-decoration:none}
/* Phones: the notice list spans the screen under the header instead of hanging off the bell */
@media(max-width:760px){.notice-pop{position:fixed;top:var(--top-h);left:var(--inset);right:var(--inset);width:auto;max-width:none}}
/* ── Theater and chat over the video, as in the design mockups (CoVid 디자인 시안) ── */
:root{--theater-info:90px}
/* Theater and phone vertical video ("immersive"): the header gives way to a top bar over the video (back, title, progress,
   settings) that hides with the player UI. Top bar and playback bar sit on YouTube's own shade: black, 98px tall, alpha by
   distance from the edge (decoded from the player's gradient image). */
:root{--yt-shade:rgba(0,0,0,.667) 0px,rgba(0,0,0,.58) 11px,rgba(0,0,0,.471) 22px,rgba(0,0,0,.353) 33px,rgba(0,0,0,.239) 44px,rgba(0,0,0,.141) 55px,rgba(0,0,0,.075) 66px,rgba(0,0,0,.031) 77px,rgba(0,0,0,.012) 88px,rgba(0,0,0,0) 98px}
.immersive.has-video .top{display:none}
.stage-top{display:none}
.immersive.has-video .stage-top{position:absolute;inset:0 0 auto;z-index:3;display:flex;align-items:center;gap:10px;height:98px;padding:0 8px 42px 4px;background:linear-gradient(to bottom,var(--yt-shade));color:#fff;pointer-events:none;transition:opacity .2s}
.stage-top>*{pointer-events:auto}
.immersive.ui-idle .stage-top{opacity:0}
.controls{transition:opacity .2s}
.has-video.ui-idle .controls{opacity:0;pointer-events:none}
.immersive.ui-idle .stage-top>*{pointer-events:none}
.stage-title{flex:1;min-width:0;font-size:14px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.stage-status{display:flex;align-items:center;gap:4px;flex-shrink:0;font-size:12px;font-weight:600}
.stage-top .icon-btn{color:#fff}
.immersive.has-video .controls{background:none}
.immersive.has-video .controls::before{content:"";position:absolute;inset:auto 0 0;height:98px;background:linear-gradient(to top,var(--yt-shade));z-index:-1;pointer-events:none}
.stage-shield{display:none}
.has-video .stage-shield{display:block;position:absolute;inset:0;z-index:1}
.has-video.ui-idle .stage-shield{cursor:none}
.theater.has-video .stage{height:min(56.25vw,calc(100dvh - var(--theater-info)))}
#stageSettings{display:none}
.theater.has-video #stageSettings{display:inline-flex}
.controls .icon-btn[aria-pressed=true]{background:rgba(255,255,255,.18)}
/* Chat panel over the video: as tall as its messages (max height set by the layout), then scrolls */
.chat.overlay{height:auto}
.chat.overlay .chat-header{padding:0 4px 0 14px;gap:10px;border-bottom-color:rgba(255,255,255,.08)}
.chat.overlay .chat-title{gap:10px}
.chat.overlay .chat-title strong{font-size:15px}
.chat.overlay .messages{flex:1 1 auto;padding:6px 0;display:flex;flex-direction:column;gap:2px}
.chat:is(.overlay,.floating) .msg{gap:10px;line-height:1.5}
.chat.overlay .compose{padding:8px 10px 10px}
.chat.overlay .compose form{background:rgba(255,255,255,.12);border-color:transparent}
/* Floating chat: no handle; the bubbles themselves are dragged. Phones show the last two. */
#chatGrip{display:none!important}
.chat.floating .messages{touch-action:none;cursor:move}
.chat.floating.compact .msg:nth-last-child(3){display:none}
.chat.compact .msg,.chat.compact .compose textarea{font-size:13px}
/* Typing on a phone: last message above a composer bar docked on the keyboard */
.chat.typing{background:transparent}
.chat.typing .chat-header{display:none}
.chat.typing .messages{display:flex;flex-direction:column;padding:0 12px 8px;background:transparent;overflow:hidden}
.chat.typing .msg:last-child{align-self:flex-start;gap:10px;line-height:1.5;font-size:13px;background:rgba(15,15,15,.5);border-radius:16px;padding:7px 12px 7px 7px}
.chat.typing .compose{padding:6px 8px 6px 12px;background:rgba(15,15,15,.9)}
.chat.typing .compose form{background:transparent;border:0;padding:0;gap:8px}
.chat.typing .compose textarea{height:40px;min-height:40px;padding:8px 16px;border-radius:20px;background:#272727;border:1px solid var(--char);font-size:14px}
.chat.typing .compose #send{width:36px;height:36px}
@media(max-width:760px){
.vertical.immersive.has-video .stage{height:100svh}
/* Back from the vertical video's top bar shows the header; the theater button returns to the full-screen view */
.vertical.has-video:not(.immersive) #theater{display:inline-flex}
.vertical.has-video .controls :is(#rewind,#forward,.volume){display:none}
/* Phone portrait: the chat fills the rest of the screen, its composer at the bottom */
body:not(.vertical):not(.theater){overflow:hidden}
body:not(.vertical):not(.theater) #root{height:100dvh;min-height:0}
body:not(.vertical):not(.theater) .room{flex:1;min-height:0;overflow:auto;grid-template-rows:auto auto minmax(320px,1fr)}
body:not(.vertical):not(.theater) .room>.chat:not(.overlay):not(.floating){height:auto;align-self:stretch}
body:not(.vertical):not(.theater).chat-hidden .room{grid-template-rows:auto auto}
}
/* Landscape phone theater: the video fills the screen; no settings in the player (as in the mockup) */
@media(max-height:500px) and (orientation:landscape){
.theater.has-video .stage{height:100dvh}
.theater.has-video #stageSettings{display:none}
}
.msg .translation{margin-top:2px;color:var(--muted);font-size:.92em;white-space:pre-wrap;overflow-wrap:anywhere}
.help dd.line{grid-column:1/-1}
/* 프롬프트 › ?: request structure */
.help-head{display:block;color:var(--text);font-weight:600}
.prompt-flow{display:grid;grid-template-columns:max-content 1fr;gap:calc(1.5 * var(--space)) calc(3 * var(--space));align-items:center;margin:var(--space) 0 calc(2 * var(--space))}
.flow-name{color:var(--text);font-weight:600;white-space:nowrap}
.flow-parts{display:flex;flex-wrap:wrap;align-items:center;gap:calc(1 * var(--space))}
.flow-plus{color:var(--muted)}
.flow-chip{padding:2px 8px;border-radius:10px;border:1px solid var(--line);background:var(--bg);color:var(--text);white-space:nowrap}
.flow-chip.guide-a{border-color:var(--brand-partner);color:var(--brand-partner)}
.flow-chip.guide-c{border-color:var(--char);color:var(--char)}
.flow-chip.guide-t{border-color:var(--muted);color:var(--muted)}
.flow-chip.data{border-style:dashed;color:var(--muted)}
/* YouTube draws its own title (top) and "Watch on YouTube" (bottom) inside the player, where CSS cannot reach.
   With .yt-crop (video at least as wide as the stage) the frame is taller than the stage by --yt-crop at both ends:
   YouTube letterboxes the video into the middle, so those overlays sit in the black bars the stage clips away. */
:root{--yt-crop:72px}
.yt-crop .player iframe{position:absolute;left:0;top:calc(-1 * var(--yt-crop));height:calc(100% + 2 * var(--yt-crop))}
/* Playback bar sizes from the mockups: 44px buttons with 2px gaps; desktop theater row 48 with 16px sides, other rows 44 with 12px;
   phones 40px buttons. Time sits 6px after the buttons. Chat send button 36px. */
.controls{padding:0 12px 4px}
.control-row{gap:2px;height:44px}
.controls .icon-btn{width:44px;height:44px}
.timecode{margin-left:6px}
.theater .controls{padding:0 16px 4px}
.theater .control-row{height:48px}
.compose #send{width:36px;height:36px}
@media(max-width:760px),(max-height:500px) and (orientation:landscape){
.controls,.theater .controls{padding:0 12px 4px}
.control-row,.theater .control-row{gap:2px;height:44px}
.controls .icon-btn{width:40px;height:40px}
}
/* Playback bar: YouTube's bottom shade in every view (not only theater) */
.controls{background:none}
.controls::before{content:"";position:absolute;inset:auto 0 0;height:98px;background:linear-gradient(to top,var(--yt-shade));z-index:-1;pointer-events:none}
/* Analysis control in the row under the video (replaces the old status row) */
.analyze-status{font-size:11px;color:var(--muted);font-variant-numeric:tabular-nums;white-space:nowrap}
.pill-icon.analyze-stop{width:32px;height:32px;margin-right:var(--space)}
.analyze-group{display:inline-flex;align-items:center;gap:calc(2 * var(--space))}
.controls .analyze-group{gap:2px}
.controls .analyze-status{color:rgba(255,255,255,.75);margin-right:6px}
.controls .pill-icon.analyze-stop{background:rgba(255,255,255,.15);color:#fff;margin-right:4px}
.chat-header .analyze-group{margin-right:2px}
#analyze.pill-icon{background:var(--inverse);color:var(--inverse-text)}
#analyze.pill-icon:not(:disabled):hover{background:var(--inverse-hover)}
.controls #analyze{background:#f1f1f1;color:#0f0f0f}
.controls #analyze:hover{background:#d9d9d9}
/* Chat header: 번역 보기 toggle and, on phones, 채팅 접기 */
#chatFold{display:none}
.translate-view{display:inline-flex;align-items:center;gap:4px;height:32px;padding:0 10px;border:0;border-radius:16px;background:var(--soft);color:var(--text);font-size:12px;font-weight:600;white-space:nowrap}
.translate-view:hover{background:var(--soft-hover)}
.msg .text.muted{color:var(--muted)}
.msg .text.second{display:block;margin-top:1em}
/* Phone portrait: the chat fills everything under the video; folding it shows the video info (and 채팅 표시) instead */
@media(max-width:760px){
body:not(.vertical):not(.theater):not(.chat-hidden) .room{grid-template-areas:"watch" "chat";grid-template-rows:auto minmax(0,1fr);overflow:hidden}
body:not(.vertical):not(.theater):not(.chat-hidden) .below{display:none}
body:not(.vertical):not(.theater):not(.chat-hidden) .room>.chat:not(.overlay):not(.floating){min-height:0}
body:not(.vertical):not(.theater) .chat:not(.overlay):not(.floating) #chatFold{display:inline-flex}
}
.story-empty{margin:0;color:var(--muted);line-height:1.6}
/* Phone portrait, chat folded: only the chat header stays, as a bar at the bottom; tapping it unfolds the chat */
@media(max-width:760px){
body:not(.vertical):not(.theater).chat-hidden .room{grid-template-areas:"watch" "below" "chat";grid-template-rows:auto minmax(0,1fr) auto;overflow:hidden}
body:not(.vertical):not(.theater).chat-hidden .below{overflow:auto;min-height:0}
body:not(.vertical):not(.theater).chat-hidden #chat{display:flex!important;height:auto!important;min-height:0;border-top:1px solid var(--line)}
body:not(.vertical):not(.theater).chat-hidden #chat>:not(.chat-header){display:none}
body:not(.vertical):not(.theater).chat-hidden .chat-header{border-bottom:0;cursor:pointer}
body:not(.vertical):not(.theater).chat-hidden #chatFold svg{transform:rotate(180deg)}
body:not(.vertical):not(.theater) #chatToggle{display:none}
}
/* ChatGPT 구독: sign-in state instead of an API key */
.oauth-line{display:flex;align-items:center;gap:calc(2 * var(--space))}
.oauth-account{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.notice-actions{display:flex;flex-wrap:wrap;gap:calc(2 * var(--space));margin-top:calc(2 * var(--space))}
.notice-steps code{font-size:.92em}
.notice-lead{margin:var(--inset) 0 0}
#extSteps .notice-steps .btn{margin-top:2px}
.notice-actions .btn.secondary[aria-pressed=true],.notice-actions .btn.secondary[aria-pressed=true]:not(:disabled):hover{background:var(--inverse);color:var(--inverse-text)}
.log-tag{flex-shrink:0;padding:1px 7px;border-radius:9px;font-size:11px;font-weight:600;white-space:nowrap;background:var(--soft);color:var(--text-2)}
.log-tag.tag-vision{background:#1a73e822;color:#4d8fe8}
.log-tag.tag-merge{background:#8e44ad22;color:#a970c4}
.log-tag.tag-plan{background:#e3740922;color:#e08a3a}
.log-tag.tag-chat{background:#1e8e3e22;color:#3aa45a}
.log-tag.tag-translate{background:#d9306522;color:#e0577f}
.log-tag.tag-captions{background:#c4302b22;color:#d65a55}
/* Playlist: 자동재생 switch (YouTube's: a 36×14 track with a 20px knob, right when on) and the separator between videos'
   conversations in the chat. */
.autonext{position:relative;flex-shrink:0;width:48px;height:40px;padding:0;border:0;background:none;cursor:pointer}
.autonext::before{content:"";position:absolute;left:6px;right:6px;top:13px;height:14px;border-radius:7px;background:rgba(255,255,255,.3)}
.autonext .knob{position:absolute;left:4px;top:10px;width:20px;height:20px;border-radius:50%;background:#717171;transition:left .15s,background .15s}
.autonext[aria-checked=true] .knob{left:24px;background:#fff}
.autonext:focus-visible{outline:2px solid #fff;outline-offset:-2px;border-radius:8px}
.msg-sep{display:flex;align-items:center;gap:8px;margin:8px 0;padding:0 var(--inset);font-size:12px;color:var(--muted);white-space:nowrap;overflow:hidden}
.msg-sep span{overflow:hidden;text-overflow:ellipsis;max-width:70%}
.msg-sep::before,.msg-sep::after{content:"";flex:1;min-width:16px;border-top:1px solid var(--line)}
@media(prefers-reduced-motion:reduce){.autonext .knob{transition:none}}
/* ── PC vertical video (Shorts), as on YouTube Shorts desktop (measured 2026-10-03): the video's tools in a column of round
   buttons beside it, the play/volume and settings circles over its top, a thin progress bar on its bottom edge, the title at
   the bottom left, and the tabs as YouTube chips. ── */
.acts,.tab-label,.tab-title,.stage-byline{display:none}
@media(min-width:761px){
.vertical .watch{display:flex;align-items:flex-end;gap:12px}
.vertical .acts{display:flex;flex-direction:column;gap:8px;padding-bottom:8px}
.act{display:flex;flex-direction:column;align-items:center;gap:4px;font-size:12px;line-height:18px;color:var(--text);white-space:nowrap}
.act :is(.pill-icon,#analyze.pill-icon){width:48px;height:48px;background:var(--soft);color:var(--text)}
.act .pill-icon:not(:disabled):not([aria-pressed=true]):hover{background:var(--soft-hover)}
.act .pill-icon[aria-pressed=true]{background:var(--inverse);color:var(--inverse-text)}
#actAnalyze .analyze-group{flex-direction:column-reverse;gap:4px}
#actAnalyze .pill-icon.analyze-stop{margin:0}
#actAnalyze .analyze-status{font-size:12px;line-height:18px;color:var(--text)}
#actAnalyze:has(#analyzeStatus:not([hidden])) .act-label{display:none}
#actAnalyze:not(:has(:is(#analyze,#analyzeStop):not([hidden]))){display:none}
/* Title block at the bottom left (avatar row, then a bold title), 18px above the video's bottom edge */
.vertical .below{padding-bottom:18px}
.vertical .below .tabs{order:1;margin:0 0 12px}
.vertical #detail{order:2}
.vertical .owner{order:3;gap:8px;margin:16px 0 0}
.vertical h1#title{order:4;font-size:19px;font-weight:700;line-height:1.4;margin:14px 0 0}
.vertical .owner .avatar.big{width:36px;height:36px;flex-basis:36px;font-size:16px}
.vertical .owner-name{font-size:14px;font-weight:400}
/* Tabs as YouTube chips: 32px, 8px radius, 0 12px, 14px/500; selected inverse, others the soft fill */
.vertical .tab-btn{width:64px;height:72px;padding:0;border-radius:12px;background:none;flex-direction:column;gap:7px;font-size:11px;line-height:1;font-weight:400;color:var(--text);opacity:.72}
.vertical .tab-btn svg{width:24px;height:24px}
.vertical .tab-label{display:inline}
.vertical .tab-btn:not(.active):hover{background:var(--soft);opacity:1}
.vertical .tab-btn.active{background:var(--soft);color:var(--text);opacity:1;font-weight:600}
/* The tabs as a rail at the far left under the header (like YouTube's 홈·Shorts·구독), the chosen tab's name over the list */
.vertical .below .tabs{position:fixed;left:0;top:calc(var(--top-h) + var(--room-top));z-index:5;width:var(--rail-w);max-height:calc(100dvh - var(--top-h) - var(--room-top));overflow-y:auto;scrollbar-width:none;flex-direction:column;flex-wrap:nowrap;align-items:center;gap:4px;margin:0}
.vertical .tab-title{display:block;order:2;margin:0 0 10px;padding-top:6px;font-size:18px;line-height:1.3;font-weight:600}
/* The list starts clear of the rail: the room is centred, so it is pushed right only as far as the rail needs (at most 160px,
   so a narrow window still leaves the list 200px) */
.vertical .below{--rail-w:72px;--shorts-w:calc(360px + var(--gap) + (100dvh - var(--top-h) - var(--room-top) - var(--gap)) * 9 / 16 + 60px);padding-left:min(160px,max(0px,calc(var(--rail-w) + 20px - (100vw - var(--shorts-w)) / 2)))}
.vertical:not(.chat-hidden) .below{--shorts-w:calc(360px + var(--gap) + (100dvh - var(--top-h) - var(--room-top) - var(--gap)) * 9 / 16 + 60px + var(--gap) + var(--chat-w))}
/* Chat open: the character row and a one-line title inside the video's bottom left, over a faint shade (YouTube Shorts with its
   comments open, measured 2026-10-04: 32px avatar, 15px name, 16px regular title, 16px in); the bar's own shade steps aside */
.vertical:not(.chat-hidden) .stage-byline{display:grid;position:absolute;left:0;right:0;bottom:0;z-index:2;gap:8px;padding:48px 16px 20px;background:linear-gradient(to top,rgba(0,0,0,.45),rgba(0,0,0,0));color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.5);pointer-events:none}
.vertical:not(.chat-hidden) .controls::before{display:none}
.stage-byline .owner{margin:0;gap:8px}
.stage-byline .owner .avatar.big{width:32px;height:32px;flex-basis:32px;font-size:15px}
.stage-byline .owner-name{font-size:15px;color:#fff}
.stage-byline h1#title{margin:0;font-size:16px;font-weight:400;line-height:22px;color:#fff;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* Player: separate translucent 48px circles 16px in from the top corners; the bar on the bottom edge stays visible */
.vertical .controls{inset:0;background:none;padding:0;pointer-events:none}
.vertical .control-row{position:absolute;top:16px;left:16px;right:16px;height:48px;gap:8px;pointer-events:none;transition:opacity .2s}
.vertical .control-row>*{pointer-events:auto}
.vertical .controls :is(#rewind,#forward,.timecode,#chatPanelBtn,#theater){display:none}
.vertical.has-video .controls #stageSettings{display:inline-flex}
.vertical .controls :is(#prevVideo,#nextVideo){width:48px;height:48px;border-radius:50%;background:rgba(40,40,40,.55);color:#fff}
.vertical .controls .autonext{height:48px;border-radius:24px;background:rgba(40,40,40,.55)}
.vertical .controls .autonext::before{top:17px}
.vertical .controls .autonext .knob{top:14px}
.vertical .controls :is(#play,#stageSettings){width:48px;height:48px;border-radius:50%;background:rgba(40,40,40,.55);color:#fff}
.vertical .controls .volume{height:48px;border-radius:24px;background:rgba(40,40,40,.55)}
.vertical .controls #mute{width:48px;height:48px;background:none;color:#fff}
.vertical #timeline{position:absolute;left:0;right:0;bottom:0;height:12px;align-items:flex-end;pointer-events:auto}
.vertical #timeline .bar{top:auto;bottom:0;margin-top:0;height:4px}
.vertical #seek{position:absolute;left:0;right:0;bottom:-4px;height:12px}
.vertical.has-video.ui-idle .controls{opacity:1}
.vertical.has-video.ui-idle .control-row{opacity:0}
.vertical.has-video.ui-idle .control-row>*{pointer-events:none}
}
/* 설정 › 로어북: like the 고급 switch lines, one row per entry with its name, keywords or 언제나 활성화, and the start of its text */
.lore-head{display:flex;justify-content:space-between;align-items:center;gap:var(--inset);font-size:14px}
.lore-count,.lore-total{font-size:12px;color:var(--muted);white-space:nowrap}
.lore-group{margin-top:18px;font-size:12px;font-weight:600;color:var(--text-2)}
.lore-folder-box{margin:12px 0 4px}
.lore-folder{display:flex;align-items:center;justify-content:space-between;gap:var(--inset);padding:8px 12px;border-radius:8px;background:var(--panel);font-size:12px;font-weight:600;color:var(--text-2);cursor:pointer}
.lore-folder-items{margin:4px 0 0 6px;padding-left:12px;border-left:2px solid var(--line)}
.lore-row{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--inset);padding:12px 0;border-bottom:1px solid var(--line)}
.lore-folder-items .lore-row:last-child{border-bottom:0}
.lore-body{flex:1;min-width:0}
.lore-body summary{display:flex;align-items:center;gap:6px;cursor:pointer;list-style:none}
.lore-body summary .fold{display:inline-flex;color:var(--muted);transition:transform .15s}
.lore-body[open] summary .fold{transform:rotate(90deg)}
.lore-body .lore-keys{display:block;margin:4px 0 0 20px}
.lore-text{display:none;margin-top:8px;pointer-events:auto;border-color:var(--line)}
.lore-body[open] .lore-text{display:block}
.lore-body summary::-webkit-details-marker{display:none}
.lore-body summary:focus-visible{outline:2px solid var(--accent);outline-offset:3px;border-radius:4px}
.lore-content{margin-top:8px;font-size:12px;line-height:1.6;white-space:pre-wrap;overflow-wrap:anywhere;color:var(--text-2)}
.lore-name{display:flex;flex-wrap:wrap;align-items:center;gap:6px;font-size:13px;font-weight:600}
.lore-badge{font-size:11px;font-weight:600;padding:1px 6px;border-radius:6px;background:var(--panel);color:var(--text-2)}
.lore-keys{font-size:11px;color:var(--muted);overflow-wrap:anywhere}
.lore-preview{font-size:12px;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.lore-row input,.lore-folder input{accent-color:var(--accent);width:18px;height:18px;flex-shrink:0;margin-top:1px}
@media(prefers-reduced-motion:reduce){.lore-body summary .fold{transition:none}}
.lore-foot{display:flex;justify-content:space-between;align-items:center;gap:12px;margin-top:16px;flex-wrap:wrap}
/* 사용량 탭: the totals line, then the receipt (per request kind: model, calls, tokens, estimated cost) */
.usage-line{line-height:1.7}
.receipt{display:grid;gap:10px;margin-top:16px;font-size:13px;color:var(--text-2)}
.r-head{display:flex;justify-content:space-between;align-items:baseline;gap:12px;flex-wrap:wrap}
.r-head b{font-size:14px;color:var(--text)}
.r-basis,.r-foot{font-size:11px;color:var(--subtle);line-height:1.7}
.r-scroll{overflow-x:auto}
.r-table{width:100%;border-collapse:collapse;font-size:13px;font-variant-numeric:tabular-nums}
.r-table th{font-size:11px;font-weight:600;color:var(--subtle);text-align:right;padding:6px 0 6px 12px;border-bottom:1px solid var(--line);white-space:nowrap}
.r-table th:first-child,.r-table td:first-child{text-align:left;padding-left:0}
.r-table td{padding:8px 0 8px 12px;text-align:right;border-bottom:1px dashed var(--line);white-space:nowrap}
.r-table td.won{color:var(--text);font-weight:600}
.r-table tr.total td{border-top:1px solid var(--muted);border-bottom:0;color:var(--text);font-weight:700;padding-top:10px}
.r-table .sub{display:block;font-size:11px;color:var(--subtle);font-weight:400}
/* A character line starts as one row, its name and three typing dots (each rising in turn); view.js shows the text after
   --typing and slides the lines (a new message, and the row growing when its text shows) as in a messenger. */
@keyframes typing-dot{0%,60%,100%{opacity:.35;transform:none}30%{opacity:1;transform:translateY(-2.5px)}}
.msg.typing .line .name{position:relative}
.msg.typing .line .text,.msg.typing .line .translation{display:none}
.typing-dots{display:none}
.msg.typing .typing-dots{display:flex;position:absolute;left:100%;top:50%;height:6px;margin:-3px 0 0 8px;gap:3.5px;align-items:center;pointer-events:none}
.typing-dots i{width:5px;height:5px;border-radius:50%;background:var(--muted);animation:typing-dot 1s infinite ease-in-out}
.typing-dots i:nth-child(2){animation-delay:.15s}
.typing-dots i:nth-child(3){animation-delay:.3s}
@media(prefers-reduced-motion:reduce){.typing-dots i{animation:none;opacity:.7}}
