/* QAlign — dark, calm, and out of the way while people are talking. */

/* ── hidden means hidden ──────────────────────────────────────────────────
   The browser's own rule is `[hidden]{display:none}` at zero specificity, so ANY
   selector that gives an element a display — `#app{display:grid}`, `.sheet{display:
   grid}`, `#wsPane{display:flex}` — quietly out-ranks it and lays the element out
   while it is invisible. A full-screen transparent box that still takes clicks is
   indistinguishable from the app being frozen, and this codebase has paid for it
   four separate times: the QuickAlign stepper, every `.sheet`, the workspace pane
   that shipped last night and made the mode button unpressable, and the four more
   found by sweeping for it (`#app`, `#recdot`, `.wscount`, `#flipBtn`).

   The nineteen hand-written `.x[hidden]{display:none}` rules below are this same fix
   applied one id at a time, and one at a time is how the fifth gets missed. So here
   is the rule itself, once, at the top. `!important` is deliberate: an element that
   is hidden and displayed at the same time is a bug by definition, so there is
   nothing legitimate for it to override. test/board-ui.mjs asserts the property over
   every element on the page carrying the attribute, rather than over the one that
   happened to break. */
[hidden]{display:none!important}

/* [stated] "An AI ... tunes into that group" — this entry point leaves room
   around the conversation, and makes the group's control visible before joining. */
.fcl .fcl-main{max-width:1240px;margin:auto;padding:0 40px 40px}
.fcl .fcl-nav{padding:23px max(28px,calc((100vw - 1160px)/2));background:var(--bg);position:relative}
.fcl .fcl-brand{min-width:0;display:block;line-height:0}.fcl .fcl-nav .fcl-brand img{width:192px;height:auto;max-width:100%}
.fcl-skip{position:fixed;left:16px;top:12px;padding:12px 18px;z-index:50;background:var(--panel);border:1px solid var(--line);border-radius:8px}
.fcl-skip:not(:focus){width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;padding:0;border:0}
/* [stated] Raise the opening view: keep both columns close to navigation. */
.fcl .fcl-hero{display:grid;grid-template-columns:1fr 1fr;gap:56px;align-items:start;padding:36px 0 56px}
.fcl .fcl-eyebrow{display:flex;align-items:center;gap:9px;font-size:11px;letter-spacing:.14em;font-weight:600;color:var(--blue-ink);margin:0 0 24px;text-transform:uppercase}
.fcl-eyebrow>span{width:6px;height:6px;background:var(--good);border-radius:50%}
.fcl h1{font:600 clamp(43px,4.65vw,64px)/1.08 var(--display);letter-spacing:-.055em;margin:0 0 27px}
.fcl h1 em{font-style:normal;color:var(--blue-ink)}
.fcl .fcl-lede{font-size:19px;line-height:1.65;color:var(--ink);margin:0 0 16px;max-width:450px}
.fcl .fcl-sub{font-size:14px;line-height:1.8;color:var(--mid);margin:0 0 30px;max-width:440px}
.fcl .fcl-primary{display:inline-flex;align-items:center;justify-content:center;gap:24px;background:var(--grad);border:0;border-radius:11px;color:var(--cloud);padding:16px 20px;font:600 13px/1.5 Inter,system-ui,sans-serif;cursor:pointer;text-decoration:none}
.fcl .fcl-primary:hover{filter:brightness(1.1);text-decoration:none}
.fcl-primary:disabled{opacity:.6;cursor:wait}
.fcl-primary>span{font-size:20px;line-height:1}
.fcl .fcl-micro{color:var(--dim);font-size:11px;margin:14px 0 0}
.fcl-preview{border:1px solid var(--line);border-radius:22px;background:linear-gradient(145deg,var(--panel2),var(--panel));box-shadow:var(--shadow);min-width:0;overflow:hidden}
.fcl-preview-top{display:flex;justify-content:space-between;gap:8px;padding:19px 20px;font-size:9px;letter-spacing:.1em;color:var(--mid);border-bottom:1px solid var(--line)}
.fcl-example{color:var(--dim);letter-spacing:0}
.fcl-demo-panel{box-sizing:border-box;min-height:0;padding:22px;display:flex;flex-direction:column;gap:15px}
.fcl-demo-heading>span{font:600 9px/1.5 Inter,system-ui,sans-serif;letter-spacing:.12em;color:var(--blue-ink)}
.fcl-demo-heading h3{font:600 21px/1.35 var(--display);letter-spacing:-.025em;margin:7px 0 0;color:var(--ink)}
.fcl-demo-conversation{display:grid;gap:10px}
.fcl-demo-message{display:grid;grid-template-columns:32px 1fr;align-items:start;gap:10px;padding:12px;border:1px solid var(--line);background:var(--panel);border-radius:12px;min-width:0}
.fcl-demo-message b{font-size:10px;color:var(--mid)}
.fcl-demo-message p{font-size:12px;line-height:1.6;color:var(--ink);margin:3px 0 0}
.fcl-demo-avatar{--person-color:var(--blue-ink);display:grid;place-items:center;width:30px;height:30px;border-radius:10px;font:700 11px Inter,system-ui,sans-serif;color:var(--person-color);background:color-mix(in srgb,var(--person-color) 13%,var(--panel));border:1px solid color-mix(in srgb,var(--person-color) 30%,transparent)}
.fcl-demo-avatar[data-person=jules]{--person-color:#9871f5}.fcl-demo-avatar[data-person=alex]{--person-color:#1ba77a}
.fcl-demo-listening{display:flex;align-items:center;gap:12px;color:var(--mid);padding:5px 0}
.fcl-demo-listening b{font-size:11px;color:var(--ink)}
.fcl-demo-listening p{font-size:11px;line-height:1.6;margin:4px 0 0}
.fcl-demo-wave{display:flex;align-items:center;justify-content:center;gap:3px;width:35px;height:32px;flex:none}
.fcl-demo-wave i{width:3px;height:13px;border-radius:3px;background:var(--blue);animation:fcl-demo-wave 1.4s ease-in-out 2 alternate}
.fcl-demo-wave i:nth-child(2){height:24px;animation-delay:-.3s}.fcl-demo-wave i:nth-child(3){height:18px;animation-delay:-.7s}.fcl-demo-wave i:nth-child(4){height:9px;animation-delay:-.5s}
@keyframes fcl-demo-wave{to{transform:scaleY(.45);opacity:.45}}
.fcl-demo-sources{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:7px}
.fcl-demo-sources>div{padding:10px 8px;background:var(--panel);border:1px solid var(--line);border-radius:10px}
.fcl-demo-sources b{display:block;font:600 10px Inter,system-ui,sans-serif;color:var(--mid);margin-bottom:7px}
.fcl-demo-sources q{font:11px/1.65 Inter,system-ui,sans-serif;color:var(--ink)}
.fcl-demo-sources mark{background:transparent;color:var(--blue-ink);text-decoration:underline;text-underline-offset:3px;text-decoration-color:color-mix(in srgb,var(--blue) 50%,transparent)}
.fcl-demo-connectors{display:block;width:100%;height:35px;flex:none;margin:-10px 0;fill:none;stroke:url(#fclDemoLinks);stroke-width:1.5}
.fcl-demo-connectors circle{fill:var(--blue);stroke:none}
.fcl-demo-reflection{padding:17px;border:1px solid color-mix(in srgb,var(--blue) 48%,var(--line));background:linear-gradient(140deg,var(--onbg),var(--panel));border-radius:12px}
.fcl-demo-tag{font:600 9px/1.5 Inter,system-ui,sans-serif;letter-spacing:.1em;color:var(--blue-ink)}
.fcl-demo-reflection>p{font:600 17px/1.5 var(--display);letter-spacing:-.015em;color:var(--ink);margin:9px 0 12px}
.fcl-demo-provenance{font:10px/1.6 Inter,system-ui,sans-serif;color:var(--mid)}
.fcl-demo-panel .fcl-demo-explainer{font:11px/1.7 Inter,system-ui,sans-serif;color:var(--mid);margin:0}
.fcl-demo-thread{font:11px/1.6 Inter,system-ui,sans-serif;color:var(--ink);margin:0;padding:10px 12px;background:var(--sunk);border:1px solid var(--line);border-radius:9px}
.fcl-demo-thread span{display:block;color:var(--dim);font-size:9px;margin-bottom:3px}
.fcl-demo-question{padding:17px;border-radius:12px;background:var(--grad-deep);border:1px solid #385ad1;color:var(--cloud)}
.fcl-demo-question .fcl-demo-tag{color:var(--cloud);opacity:.8}
.fcl-demo-question p{color:var(--cloud);font:600 19px/1.45 var(--display);letter-spacing:-.02em;margin:9px 0 0}
.fcl-demo-try>span{display:block;font:10px/1.5 Inter,system-ui,sans-serif;color:var(--mid);margin-bottom:8px}
.fcl-demo-options{display:flex;gap:7px;flex-wrap:wrap}
.fcl-demo-options button{flex:1;min-width:95px;min-height:40px;background:var(--panel);border:1px solid var(--line);color:var(--ink);font:500 10px/1.5 Inter,system-ui,sans-serif;border-radius:9px;padding:8px;cursor:pointer}
.fcl-demo-options button:hover,.fcl-demo-options button[aria-pressed=true]{border-color:var(--blue);background:var(--onbg)}
.fcl-demo-reply{box-sizing:border-box;min-height:80px;padding:12px;border:1px dashed var(--line);border-radius:10px}
.fcl-demo-reply b{font:600 9px/1.5 Inter,system-ui,sans-serif;letter-spacing:.06em;color:var(--dim)}
.fcl-demo-reply p{font:11px/1.6 Inter,system-ui,sans-serif;margin:5px 0 0;color:var(--mid)}
.fcl-demo-reply.has-reply{border-style:solid;border-color:color-mix(in srgb,var(--good) 40%,var(--line));background:color-mix(in srgb,var(--good) 6%,var(--panel))}
.fcl-demo-reply.has-reply b{color:var(--good)}.fcl-demo-reply.has-reply p{color:var(--ink)}
.fcl-demo-next{margin-top:auto;display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:40px;padding:9px 0 0;background:transparent;border:0;border-top:1px solid var(--line);color:var(--blue-ink);font:600 11px/1.5 Inter,system-ui,sans-serif;text-align:left;cursor:pointer}
.fcl-demo-next>span{font-size:19px}
.fcl-example-tabs{display:flex;gap:5px;border-bottom:1px solid var(--line);padding:10px;background:var(--panel)}
.fcl-example-tabs button{flex:1;min-width:0;min-height:44px;padding:10px 4px;border:1px solid transparent;border-radius:9px;background:transparent;color:var(--mid);font:600 11px Inter,system-ui,sans-serif;cursor:pointer}
.fcl-example-tabs button:hover{background:var(--sunk)}
.fcl-example-tabs button[aria-selected=true]{background:var(--onbg);border-color:color-mix(in srgb,var(--blue) 45%,var(--line));color:var(--blue-ink)}
@media(prefers-reduced-motion:reduce){.fcl-demo-wave i{animation:none}}
@media(max-width:700px){.fcl-demo-panel{padding:18px}.fcl-demo-heading h3{font-size:20px}.fcl-demo-options button{min-height:44px}.fcl-demo-next{min-height:44px}}
@media(max-width:360px){.fcl-demo-panel{padding:16px;gap:13px}.fcl-demo-reflection{padding:13px}.fcl-demo-question{padding:14px}.fcl-demo-question p{font-size:17px}.fcl-demo-sources q{font-size:10px}}
.fcl .fcl-how{display:grid;grid-template-columns:1fr 1.55fr;gap:55px;border-top:1px solid var(--line);border-bottom:1px solid var(--line);padding:62px 0}
.fcl h2{font:600 32px/1.22 var(--display);letter-spacing:-.035em;margin:0 0 20px}
.fcl-principles{display:grid;grid-template-columns:repeat(3,1fr);gap:23px}
.fcl-principles article>span{font:11px var(--mono);color:var(--blue-ink)}
.fcl-principles h3{font:600 14px/1.45 var(--display);margin:17px 0 10px}
.fcl-principles p{color:var(--mid);font-size:12px;line-height:1.8;margin:0}
.fcl .fcl-setup{display:grid;grid-template-columns:1fr 1.55fr;gap:55px;padding:76px 0 60px;scroll-margin-top:20px}
.fcl-setup-copy>p:not(.fcl-eyebrow){font-size:14px;color:var(--mid);line-height:1.8;max-width:310px}
.fcl-control-note{display:flex;align-items:center;gap:14px;color:var(--blue-ink);margin-top:35px}
.fcl-control-note>span{font-size:36px}
.fcl-control-note p{font-size:12px;line-height:1.7;color:var(--mid);margin:0}
.fcl-form{border:1px solid var(--line);border-radius:18px;padding:25px;background:var(--panel)}
.fcl-form fieldset{margin:0 0 22px;padding:0;border:0;min-width:0}
.fcl-form legend,.fcl-form label{color:var(--ink);font-size:12px;font-weight:600}
.fcl-form legend{padding:0;margin-bottom:12px}
.fcl-roles{display:grid;grid-template-columns:repeat(3,1fr);gap:8px}
.fcl-roles button{--role-color:var(--blue-ink);position:relative;background:var(--sunk);border:1px solid var(--line);border-radius:12px;text-align:left;color:var(--mid);padding:14px;cursor:pointer;min-width:0;transition:transform .18s ease,border-color .18s ease,background .18s ease,box-shadow .18s ease}
.fcl-roles [data-role=mirror]{--role-color:#1687ec}
.fcl-roles [data-role=facilitator]{--role-color:#0caa9b}
.fcl-roles [data-role=synthesizer]{--role-color:#9871f5}
.fcl-roles [data-role=challenger]{--role-color:#d99a23}
.fcl-roles [data-role=coach]{--role-color:#2da971}
.fcl-roles [data-role=brainstormer]{--role-color:#ec6aaa}
.fcl-roles [data-role=mediator]{--role-color:#46a9c9}
.fcl-roles button[aria-pressed=true]{border-color:var(--role-color);background:color-mix(in srgb,var(--role-color) 11%,var(--sunk));box-shadow:0 0 0 1px color-mix(in srgb,var(--role-color) 22%,transparent)}
.fcl-role-icon{display:grid;place-items:center;width:38px;height:38px;border-radius:12px;background:color-mix(in srgb,var(--role-color) 14%,var(--panel));color:var(--role-color);border:1px solid color-mix(in srgb,var(--role-color) 25%,transparent);margin-bottom:12px;transition:transform .18s ease}
.fcl-role-icon svg{width:24px;height:24px}
.fcl-role-check{position:absolute;right:12px;top:12px;width:17px;height:17px;color:var(--role-color);opacity:0;transform:scale(.6);transition:opacity .18s ease,transform .18s ease}
.fcl-roles button[aria-pressed=true] .fcl-role-check{opacity:1;transform:scale(1)}
.fcl-roles b{display:block;color:var(--ink);font-size:12px;margin-bottom:5px}
.fcl-roles span{font-size:10px;line-height:1.6;display:block}
.fcl-action-label{display:inline-flex;align-items:center;gap:10px;font:inherit}
.fcl-action-label svg{width:20px;height:20px;flex:none}
.fcl-example-tabs button{display:flex;align-items:center;justify-content:center;gap:6px}
.fcl-example-tabs svg{width:14px;height:14px;flex:none}
@media(hover:hover){.fcl-roles button:hover{transform:translateY(-3px);border-color:var(--role-color);box-shadow:0 6px 18px color-mix(in srgb,var(--role-color) 13%,transparent)}.fcl-roles button:hover .fcl-role-icon{transform:rotate(-5deg) scale(1.06)}}
.fcl-roles button:active{transform:scale(.98)}
@media(prefers-reduced-motion:reduce){.fcl-roles button,.fcl-role-icon,.fcl-role-check{transition:none!important;transform:none!important}}
.fcl-form .fcl-join{padding-bottom:22px;border-bottom:1px solid var(--line)}
.fcl-join input[type=text]{display:block;box-sizing:border-box;width:100%;font:12px/1.5 Inter,system-ui,sans-serif;background:var(--sunk);border:1px solid var(--line);border-radius:8px;color:var(--ink);padding:12px 10px;margin-top:8px}
.fcl-devices{display:flex;flex-wrap:wrap;gap:12px 22px;margin-top:14px}
.fcl-devices label{display:flex;align-items:center;gap:7px;font-weight:500;color:var(--mid)}
.fcl-devices input{width:16px;height:16px;accent-color:var(--blue);margin:0}
html.fcl-starting #gate{display:none!important}
.fcl-start-progress{position:fixed;inset:0;z-index:10000;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:24px;background:var(--bg);color:var(--ink);text-align:center;font:14px/1.6 Inter,system-ui,sans-serif}
.fcl-start-progress p{margin:0}.fcl-start-progress p:first-child{font:600 24px/1.4 var(--display)}
.fcl-start-progress p:nth-child(2){color:var(--mid)}.fcl-start-progress a{color:var(--blue-ink);margin-top:12px}
.fcl-form-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;margin-bottom:20px}
.fcl-slider{min-width:0;padding:14px;border:1px solid var(--line);border-radius:12px;background:var(--sunk)}
.fcl-slider-top{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:7px}
.fcl-slider-top output{color:var(--blue-ink);font:600 10px/1.5 Inter,system-ui,sans-serif;background:var(--onbg);border-radius:20px;padding:3px 8px}
.fcl-slider input[type=range]{--range-progress:100%;appearance:none;-webkit-appearance:none;display:block;width:100%;height:36px;margin:10px 0 0;background:transparent;cursor:ew-resize;touch-action:pan-y}
#fclCadence{--range-progress:33.333%}
.fcl-slider input[type=range]::-webkit-slider-runnable-track{height:7px;border-radius:8px;background:linear-gradient(90deg,var(--blue),var(--violet)) 0/var(--range-progress) 100% no-repeat,var(--line)}
.fcl-slider input[type=range]::-moz-range-track{height:7px;border-radius:8px;background:linear-gradient(90deg,var(--blue),var(--violet)) 0/var(--range-progress) 100% no-repeat,var(--line)}
.fcl-slider input[type=range]::-webkit-slider-thumb{appearance:none;-webkit-appearance:none;width:21px;height:21px;margin-top:-7px;border:3px solid var(--blue);border-radius:50%;background:var(--panel);box-shadow:0 0 0 4px color-mix(in srgb,var(--blue) 14%,transparent)}
.fcl-slider input[type=range]::-moz-range-thumb{width:15px;height:15px;border:3px solid var(--blue);border-radius:50%;background:var(--panel);box-shadow:0 0 0 4px color-mix(in srgb,var(--blue) 14%,transparent)}
.fcl-slider:focus-within{border-color:var(--blue)}
.fcl-slider input[type=range]:focus-visible{outline:none}
.fcl-slider input[type=range]:focus-visible::-webkit-slider-thumb{box-shadow:0 0 0 3px var(--panel),0 0 0 5px var(--blue-ink)}
.fcl-slider input[type=range]:focus-visible::-moz-range-thumb{box-shadow:0 0 0 3px var(--panel),0 0 0 5px var(--blue-ink)}
.fcl-range-stops{display:flex;justify-content:space-between;gap:6px;color:var(--dim);font:500 10px/1.5 Inter,system-ui,sans-serif}
.fcl-range-stops .current{color:var(--blue-ink);font-weight:700}
.fcl-slider>p{margin:12px 0 0;color:var(--mid);font:11px/1.6 Inter,system-ui,sans-serif}
.fcl-delivery{margin:0}
.fcl-delivery legend{padding:0 5px;font-size:12px;font-weight:600;color:var(--ink)}
.fcl-delivery-options{display:grid;grid-template-columns:1fr 1fr;gap:6px;padding:4px;border:1px solid var(--line);border-radius:11px;background:var(--panel)}
.fcl-delivery-options label{position:relative;margin:0;cursor:pointer;min-width:0}
.fcl-delivery-options input{position:absolute;inset:0;opacity:0;width:100%;height:100%;margin:0;cursor:pointer}
.fcl-delivery-options span{display:flex;align-items:center;justify-content:center;min-height:44px;padding:6px;border-radius:7px;color:var(--mid);font:600 11px/1.4 Inter,system-ui,sans-serif;text-align:center}
.fcl-delivery-options input:checked+span{background:var(--grad);color:var(--cloud);box-shadow:0 2px 8px color-mix(in srgb,var(--blue) 18%,transparent)}
.fcl-delivery-options input:focus-visible+span{outline:2px solid var(--blue-ink);outline-offset:2px}


.fcl-form label{display:block;line-height:1.5}
.fcl-form select,.fcl-form textarea{display:block;box-sizing:border-box;width:100%;font:12px/1.5 Inter,system-ui,sans-serif;background:var(--sunk);border:1px solid var(--line);border-radius:8px;color:var(--ink);padding:12px 10px;margin-top:8px;resize:vertical}
.fcl-optional{color:var(--dim);font-weight:400;margin-left:5px}
.fcl .fcl-availability{font-size:11px;line-height:1.6;color:var(--mid);margin:18px 0 12px}
.fcl-form .fcl-primary{width:100%;justify-content:space-between;box-sizing:border-box}
.fcl .fcl-after{font-size:11px;line-height:1.65;color:var(--dim);margin:12px 0 0}
.fcl .fcl-grounding{display:grid;grid-template-columns:1fr 1.55fr;gap:55px;padding:30px 0 40px;border-top:1px solid var(--line)}
.fcl-grounding b{font-size:13px}.fcl-grounding p{font-size:12px;line-height:1.8;color:var(--mid);margin:0}
.fcl .docfoot{justify-content:space-between}.fcl .docfoot .footwm{width:125px;height:auto}
.fcl input:focus-visible,.fcl button:focus-visible,.fcl a:focus-visible,.fcl select:focus-visible,.fcl textarea:focus-visible{outline:2px solid var(--blue-ink);outline-offset:4px}

/* A facilitator panel is reused across state pushes so a live microphone cannot
   replace a question someone is in the middle of typing. */
.fac-panel{display:grid;gap:12px;min-width:0}
.fac-head{display:flex;align-items:center;justify-content:space-between;gap:12px}
.fac-panel .fac-head h3{margin:0;font:600 16px var(--display);text-transform:none;letter-spacing:-.01em;color:var(--ink)}
.fac-stop{border:1px solid var(--offline);border-radius:8px;color:var(--offink);background:var(--offbg);padding:7px 11px;font:600 11px Inter,system-ui,sans-serif;cursor:pointer}
.fac-status{display:flex;align-items:center;gap:7px;font-size:11px;color:var(--good);line-height:1.5}
.fac-status::before{content:'';width:6px;height:6px;border-radius:50%;background:currentColor;flex:0 0 auto}
.fac-status.unavailable{color:var(--warn)}
.fac-intro{font-size:12px;line-height:1.7;color:var(--mid);margin:0}
.fac-controls{padding:13px;background:var(--sunk);border:1px solid var(--line);border-radius:10px;display:grid;gap:11px;min-width:0}
.fac-controls>summary{font-size:12px;font-weight:600;color:var(--ink);cursor:pointer}
.fac-controls[open]>summary{margin-bottom:12px}
.fac-fields{display:grid;grid-template-columns:1fr 1fr;gap:11px}
.fac-panel label{font-size:11px;color:var(--mid);display:grid;gap:6px;min-width:0}
.fac-panel select,.fac-panel textarea,.fac-panel input{width:100%;box-sizing:border-box;padding:9px 10px;border:1px solid var(--edge);background:var(--panel);color:var(--ink);font:12px/1.5 Inter,system-ui,sans-serif;border-radius:7px;min-width:0}
.fac-panel textarea{resize:vertical}.fac-focus-label{grid-column:1/-1}
.fac-panel select:disabled,.fac-panel textarea:disabled{opacity:.65}
.fac-control-help{font-size:10px;line-height:1.6;color:var(--dim);margin:10px 0 0}
.fac-ask{display:grid;gap:8px;border-top:1px solid var(--line);padding-top:13px}
.fac-ask .btn{font-size:11px;justify-self:start}
.fac-notes{display:grid;gap:10px}.fac-reflection{padding:13px;border:1px solid var(--line);border-left:2px solid var(--blue);border-radius:8px;background:var(--panel)}
.fac-reflection-head{display:flex;justify-content:space-between;gap:8px;color:var(--blue-ink);font-size:9px;text-transform:uppercase;letter-spacing:.07em}
.fac-reflection p{margin:8px 0 0;color:var(--ink);font-size:12px;line-height:1.75;overflow-wrap:anywhere}
.fac-evidence{margin:10px 0 0;padding:8px 0 0;border-top:1px solid var(--line);font-size:10px;line-height:1.7;color:var(--mid)}
.fac-evidence cite{display:block;font-style:normal;color:var(--dim)}
.fac-history-title{font-size:11px;color:var(--dim);margin:2px 0 0;font-weight:500}
.fac-empty{font-size:12px;line-height:1.7;color:var(--mid);padding:15px;border:1px dashed var(--edge);border-radius:9px;margin:0}
@media(max-width:950px){.fcl .fcl-main{padding:0 26px 30px}.fcl .fcl-hero{gap:30px;padding:32px 0 48px}.fcl .fcl-how,.fcl .fcl-setup,.fcl .fcl-grounding{grid-template-columns:1fr 1.5fr;gap:30px}.fcl-principles{grid-template-columns:1fr;gap:20px}.fcl-principles article{display:grid;grid-template-columns:24px 1fr;column-gap:10px}.fcl-principles article>span{padding-top:3px}.fcl-principles h3{margin:0 0 5px}.fcl-principles p{grid-column:2}.fcl-roles{grid-template-columns:1fr 1fr}.fcl-nav .docnav-right>a:first-child{display:none}}
@media(max-width:700px){.fcl .fcl-main{padding:0 22px 30px}.fcl .fcl-nav{padding:20px 22px;gap:18px}.fcl .fcl-nav .fcl-brand img{width:145px}.fcl .docnav-right{gap:12px}.fcl .fcl-hero{grid-template-columns:1fr;gap:38px;padding:28px 0 38px}.fcl h1{font-size:47px}.fcl .fcl-lede{font-size:17px}.fcl .fcl-how,.fcl .fcl-setup,.fcl .fcl-grounding{grid-template-columns:1fr;gap:24px;padding:38px 0}.fcl h2{font-size:29px}.fcl-setup-copy>p:not(.fcl-eyebrow){max-width:100%}.fcl-control-note{display:none}.fcl-form{padding:18px}.fcl-preview{max-width:520px;width:100%;justify-self:center}.fcl .fcl-eyebrow{margin-bottom:19px}.fcl-form-row{grid-template-columns:1fr}.fcl .docfoot{gap:22px}.fcl .docfoot nav{gap:13px}.fcl .docfoot>span{font-size:11px}}
@media(max-width:360px){.fcl .fcl-main{padding-left:16px;padding-right:16px}.fcl .fcl-nav{padding:18px 16px}.fcl .fcl-nav .fcl-brand img{width:125px}.fcl h1{font-size:40px}.fcl .fcl-primary{font-size:12px;gap:14px;padding:14px}.fcl-preview-top{padding:16px 12px;font-size:8px}.fcl-roles button{padding:10px}}
@media(prefers-reduced-motion:reduce){.fcl *{scroll-behavior:auto!important}}

:root{
  /* Brand — Team Meet, option 9. Electric blue through hyper violet on midnight. */
  --blue:#0794FC; --signal:#0773F9; --royal:#0755EB; --deep:#042D97;
  /* --blue is the BRAND blue and belongs on borders, fills and dark backgrounds. It is
     3.16:1 on white, so it fails AA as text in light mode — the "Follow" toggle and
     every speaker name in the transcript were unreadable there. --blue-ink is the same
     blue where the background is dark and the already-darkened accent where it is
     light, so a rule can say "blue text" without having to know the theme. */
  --blue-ink:#0794FC;
  --indigo:#1D2FC6; --violet:#5B2EF2; --midnight:#050817; --cloud:#F8FAFF;
  --grad:linear-gradient(135deg,#0794FC 0%,#0755EB 48%,#5B2EF2 100%);
  --grad-deep:linear-gradient(135deg,#042D97 0%,#1D2FC6 55%,#5B2EF2 100%);

  --bg:#050817; --panel:#0A0E24; --panel2:#0F1430; --line:#1C2350;
  --ink:#F8FAFF; --mid:#9AA6C8; --dim:#74809A;
  --acc:#0794FC;          /* interactive, the brand's own blue */
  --acc2:#5B2EF2;         /* the second half of the gradient */
  --good:#2BD9A6;         /* verified / aligned — a semantic, not a brand colour */
  --warn:#F5B851;         /* unverified, open */
  --bad:#FF6B7A;          /* block */
  --r:16px;
  --mono:ui-monospace,SFMono-Regular,Menlo,monospace;
  --display:'Sora',system-ui,sans-serif;

  /* Surfaces, named by depth rather than by colour, so a light theme is a matter of
     redefining ten values instead of hunting through the file. */
  --field:#0d1218;        /* sunken: inputs, meters, tab strips */
  --sunk:#141a24; --sunk2:#16233a;
  --hair:#1c2230;         /* dividers inside a card */
  --edge:#2b3444; --edge2:#2a3a5c;
  --deepbg:#070B1C; --panel3:#151b3d;
  --chipbg:rgba(8,11,16,.72);
  --hover:#1d2430;
  --stage:#05070f;        /* behind the video, where no tile reaches */
  --shadow:0 18px 44px -18px rgba(0,0,0,.8);
  --scrim:rgba(5,8,23,.72);
  --tint:0;               /* 1 in light mode — lets a rule ask which theme it is in */
  --offbg:#3a1f24; --offline:#5b2b31; --offink:#ffb4b4;   /* muted / camera off / leave */
  --onbg:#0d1b4a;  --online:#2440a8;                      /* a control that is engaged */
}

/* ═══════════════════════ light mode ═══════════════════════
   Not a preference. A working light.

   A laptop screen is the only lamp most people have pointed at their face, and a dark
   interface wastes it: in an unlit room a dark UI leaves you a silhouette. A light one
   turns the panel into a softbox. That is the whole reason this exists, which is also
   why the key light below sits in the same settings block — the theme lifts the room,
   the key light does the actual work.

   Semantic colours are re-picked rather than reused: --good at #2BD9A6 is legible on
   midnight and nearly invisible on white. */
:root[data-theme="light"]{
  --bg:#F4F6FC; --panel:#FFFFFF; --panel2:#F7F9FF; --panel3:#EEF2FE;
  --line:#DCE2F2;
  --ink:#0C1024; --mid:#4A5473; --dim:#5C6684;
  --acc:#0B4FD6; --acc2:#5124D8;    /* darkened for text: the brand blue is 3.2:1 on white */
  --blue-ink:#0B4FD6;
  --good:#0E7C57; --warn:#8A5600; --bad:#B81F33;
  --field:#FFFFFF; --sunk:#F1F4FD; --sunk2:#E9EFFE;
  --hair:#E4E9F6; --edge:#CED6EB; --edge2:#BFC9E6;
  --deepbg:#FFFFFF;
  --chipbg:rgba(8,11,16,.72);   /* over video — deliberately NOT flipped */
  --hover:#EDF1FC;
  --stage:#E7EBF6;
  --shadow:0 14px 34px -16px rgba(16,24,58,.28);
  --scrim:rgba(244,246,252,.78);
  --tint:1;
  --offbg:#FDE9EC; --offline:#F3C2CA; --offink:#B02236;
  --onbg:#E6EEFE;  --online:#B9CDF7;
}
/* "Match my system" is the default, so an un-stamped document follows the OS. */
@media (prefers-color-scheme: light){
  :root:not([data-theme="dark"]){
    --bg:#F4F6FC; --panel:#FFFFFF; --panel2:#F7F9FF; --panel3:#EEF2FE;
    --line:#DCE2F2;
    --ink:#0C1024; --mid:#4A5473; --dim:#5C6684;
    --acc:#0B4FD6; --acc2:#5124D8; --blue-ink:#0B4FD6;
    --good:#0E7C57; --warn:#8A5600; --bad:#B81F33;
    --field:#FFFFFF; --sunk:#F1F4FD; --sunk2:#E9EFFE;
    --hair:#E4E9F6; --edge:#CED6EB; --edge2:#BFC9E6;
    --deepbg:#FFFFFF;
    --chipbg:rgba(8,11,16,.72);   /* over video — deliberately NOT flipped */
    --hover:#EDF1FC;
    --stage:#E7EBF6;
    --shadow:0 14px 34px -16px rgba(16,24,58,.28);
    --scrim:rgba(244,246,252,.78);
    --tint:1;
    --offbg:#FDE9EC; --offline:#F3C2CA; --offink:#B02236;
    --onbg:#E6EEFE;    --online:#B9CDF7;
  }
}
*{box-sizing:border-box}
html,body{height:100%}
body{
  margin:0;background:var(--bg);color:var(--ink);
  font:15px/1.55 'Inter',-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif;
  -webkit-font-smoothing:antialiased;overflow:hidden;
}
button{font:inherit;color:inherit;cursor:pointer;border:0;background:none}
input,textarea,select{font:inherit;color:inherit}
a{color:var(--acc2)}

/* ───────── door ───────── */
.site{position:fixed;inset:0;z-index:50;overflow-y:auto;background:var(--bg)}
.site.gone{opacity:0;pointer-events:none;transition:opacity .45s}
.gate-inner{width:min(460px,92vw);text-align:center}
.mark{display:none}
.gate h1{margin:0;font-size:34px;letter-spacing:-.02em;font-weight:650}
.tag{margin:.5rem 0 1.6rem;color:var(--mid)}
#gateForm{display:grid;gap:8px}
#gateForm input{background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:12px 14px;outline:none}
#gateForm input:focus{border-color:var(--acc2)}
.primary{background:var(--grad);color:#fff;font-weight:650;
  border-radius:10px;padding:12px;margin-top:4px}
.primary:disabled{opacity:.5}
.gate-toggles{display:flex;gap:16px;justify-content:center;margin:14px 0 0;color:var(--mid);font-size:13px}
.gate-toggles label{display:flex;gap:6px;align-items:center;cursor:pointer}
.arc{list-style:none;display:grid;grid-template-columns:repeat(4,1fr);gap:6px;margin:26px 0 0;padding:0;
  text-align:left;font-size:11px;color:var(--dim)}
.arc li{border-top:2px solid var(--line);padding-top:8px}
.arc li:first-child{border-color:var(--acc2)}
.arc b{display:block;color:var(--mid);font-weight:600;font-size:12px}
.gate-foot{margin-top:22px;font-size:12px;color:var(--dim)}

/* ───────── room shell ───────── */
#app{position:fixed;inset:0;display:grid;background:var(--bg);
  grid-template-columns:1fr 400px;grid-template-rows:1fr 60px;
  grid-template-areas:"stage rail" "bar rail";}
#app.norail{grid-template-columns:1fr 0;}
#app.norail #rail{display:none}
#stage{grid-area:stage;position:relative;padding:12px;overflow:hidden;min-width:0}
/* min-width:0 matters: without it a wide control row stretches the grid column and
   pushes the side panel off the right edge of the window. Adding two buttons to the
   bar did exactly that. */
/* The control bar owns its own stacking context so anything that pops UP out of it —
   the reaction tray — lands above the video strip instead of behind it. overflow is
   visible for the same reason; the bar clips horizontally via its children instead. */
#bar{grid-area:bar;position:relative;z-index:10;display:flex;align-items:center;
  justify-content:space-between;padding:0 14px;gap:10px;min-width:0;
  border-top:1px solid var(--line);background:var(--panel)}
.bar-mid{overflow:visible}
#rail{grid-area:rail;border-left:1px solid var(--line);background:var(--panel);display:flex;flex-direction:column;min-width:0}

/* ───────── video grid ───────── */
/* The grid owns the stage, until someone presents — then the screen does and the
   faces become a strip. An inline height here would fight the flex column and the
   filmstrip would silently cover the presentation. */
#stage{--striph:118px}   /* the strip of faces: one number, read by the grid, the picture and the captions */
#grid{flex:1;min-height:0;display:flex;flex-direction:column;gap:10px}
#stagearea{display:grid;gap:10px;flex:1;min-height:0;align-content:center;justify-content:center;
  grid-auto-rows:1fr}
#strip{display:flex;gap:8px;justify-content:center;flex:none;height:118px}
#strip[hidden]{display:none}
#strip .tile{width:auto;aspect-ratio:4/3;height:100%}
/* (There was a rule here forcing speaker view to ONE column and ONE row with
   !important — left from the first day, when the faces along the bottom lived in a
   separate #strip. Once they became cells of this grid it overrode every template
   renderGrid set: the stage lost half its width, the faces were pushed into implicit
   columns, and your own corner picture landed on top of them. renderGrid owns the
   template now; nothing here may override it.) */
.viewbtn{display:none;position:absolute;right:16px;top:16px;z-index:5;width:38px;height:38px;border-radius:10px;
  background:rgba(8,11,16,.75);border:1px solid var(--line);color:var(--mid);font-size:15px;
  backdrop-filter:blur(6px)}
.viewbtn:hover{color:var(--ink);border-color:var(--blue)}
.viewbtn[hidden]{display:none}
.panelbtn{background:var(--panel2);border:1px solid var(--line);border-radius:10px;padding:8px 13px;
  font-size:12.5px;color:var(--mid);white-space:nowrap}
.panelbtn:hover{border-color:var(--blue);color:var(--ink)}
.panelbtn[hidden]{display:none}
.closebtn{display:flex;align-items:center;gap:5px;border:1px solid var(--line);border-radius:9px;padding:5px 10px}
.closebtn:hover{border-color:var(--blue);color:var(--ink)}
.closebtn span{font-size:12px}
.closebtn i{font-style:normal;line-height:1}
.closebtn .chev-l{display:none}
.tile{position:relative;background:#0e1218;border:1px solid var(--line);border-radius:var(--r);
  overflow:hidden;display:grid;place-items:center;min-height:0}
/* [stated] "my view versus hers it shouldnt cut that video feed into anything other
   than what it actually is (zoom is good at boxing these in)". `cover` fills the tile
   by cropping whatever does not fit — which on a portrait phone camera in a landscape
   tile means most of the person. `contain` shows the camera's real frame and lets the
   tile letterbox around it, which is what Zoom does and why its gallery never cuts a
   face in half. The ground behind it is the stage colour, so the box reads as
   deliberate rather than as a gap.

   The strip and the picture-in-picture keep `cover`: those are thumbnails a few
   centimetres wide, where letterboxing spends more than the crop costs. */
.tile video{width:100%;height:100%;object-fit:contain;background:#0e1218}
/* [stated] "His mobile video is cut to only the top — I need to see all of him."
   A phone held upright sends a portrait picture. As a grid child with
   `height:100%`, the video's height was resolving to its own intrinsic height
   inside the 16:9 tile — a portrait frame at the tile's full width is far taller
   than the tile, the tile clips overflow, and what was left on screen was the
   ceiling and the top of a head. Absolutely positioned against the tile the box is
   the tile's, whatever the picture's shape, and `contain` does the rest: a portrait
   picture sits whole between two dark bars, the way Meet and Zoom show it. */
.tile video{position:absolute;inset:0;width:100%;height:100%;max-height:100%}
#stagearea.focused .tile.instrip video, .tile.selfpip video{object-fit:cover}
/* A portrait picture in a thumbnail is cropped to its middle, where the face is. */
.tile video.portrait{object-position:center 30%}
#stagearea.focused .tile.instrip video.portrait, .tile.selfpip video.portrait{object-position:center 25%}
/* [stated] "on mobile the very thin border glow on whos talking is working but thats
   not working right on desktop". The ring was an OUTSET box-shadow, and
   `#stagearea .tile` carries `contain: layout paint` — which clips everything painted
   outside the element's box. On the desktop stage the glow was drawn and immediately
   clipped away; the phone layout does not go through that container, which is why it
   survived there and nowhere else. Drawn inside the box it cannot be clipped, and it
   reads the same. */
.tile.speaking{border-color:var(--good);box-shadow:inset 0 0 0 2px rgba(43,217,166,.55)}
.tile .avatar{width:var(--av,76px);height:var(--av,76px);border-radius:50%;display:grid;place-items:center;
  position:relative;background:var(--panel2);color:var(--mid);font-size:calc(var(--av,76px) * .37);font-weight:600;
  transition:transform .18s ease}
.tile .chip{position:absolute;left:10px;bottom:10px;display:flex;gap:6px;align-items:center;
  background:var(--chipbg);border-radius:8px;padding:4px 9px;font-size:12px;backdrop-filter:blur(6px)}
.tile .chip .role{color:var(--dim);font-size:10px;text-transform:uppercase;letter-spacing:.06em}
.tile .chip .muted-i{color:var(--bad)}
/* The badge used to be positioned absolutely at the chip's own coordinates and then
   pushed sideways by its OWN width — so it lined up only when the two happened to be
   the same size, and their bottoms aligned rather than their centres. It is a child of
   the chip now: one flex row, one gap, nothing to keep in sync. */
.tile .chip .badge{font-size:9.5px;line-height:1;letter-spacing:.07em;text-transform:uppercase;
  color:#fff;background:var(--grad);border-radius:5px;padding:4px 6px;font-weight:700;
  pointer-events:none;white-space:nowrap;margin-left:1px;align-self:center;
  transform:translateY(-.5px)}



/* The caption strip sits under the stage, not on top of a face. It used to overlap the
   name chip on the bottom-left tile, which is exactly where a person's name lives. */
/* Above every tile, always. Captions are the one thing on this screen that somebody
   may be depending on to follow the meeting at all. */
.captions{position:absolute;left:50%;transform:translateX(-50%);bottom:62px;
  width:min(760px,calc(100% - 40px));pointer-events:none;z-index:11;
  display:flex;flex-direction:column;align-items:center;justify-content:flex-end;gap:4px}
/* bottom:62px clears the name chip in the corner at every size; the pills are
   centred and sized to their text, so they only reach the corner if a line is long
   enough to deserve the whole width — and then they are above it, not on it. */
.captions.off{display:none}

/* ───────── the caption pills ─────────
   Two, the same size. The settled one is what was just said; the live one is what is
   being said, kept to a single line so its height can never change — the settled line
   above it therefore never moves. See drawCaptions() for the width ratchet that stops
   the live pill twitching narrower on a recogniser revision.

   Sized to content and centred, so a short sentence is a short pill, not a bar. */
.cap-pill{display:block;max-width:100%;box-sizing:border-box;padding:7px 14px;
  border-radius:10px;background:rgba(4,7,20,.86);border:1px solid rgba(28,35,80,.9);
  backdrop-filter:blur(10px);box-shadow:0 10px 30px rgba(0,0,0,.4);
  font-size:15px;line-height:1.45;color:#EAF0FF;text-align:left;overflow-wrap:anywhere;
  transition:opacity .2s ease}
.cap-pill b{color:var(--blue);font-weight:600}
.cap-pill.settled{opacity:.72}
.cap-pill.live{white-space:nowrap;overflow:hidden;color:var(--mid)}
.cap-pill.live b{color:var(--dim)}
/* The live slot is always there, one line tall, whether or not anything is in it. If
   it collapsed when empty, the settled line above would drop a slot every time a
   sentence finished and climb back when the next one started — twice per sentence,
   which is the jump this whole file exists to prevent. Invisible costs nothing;
   moving costs everything. */
.cap-pill.live{min-height:calc(1.45em + 16px)}
.cap-pill.is-empty{visibility:hidden}
.cap-pill.settled.is-empty{display:none}     /* above the live slot: collapsing it moves nothing */
@media (max-width:700px){ .cap-pill{font-size:13.5px;padding:6px 10px} .captions{bottom:56px} }

/* ───────── bar ───────── */
.bar-left,.bar-right{display:flex;align-items:center;gap:10px;min-width:0;flex:0 1 auto}
.bar-right{justify-content:flex-end}
.bar-mid{display:flex;gap:7px;min-width:0;flex:0 1 auto}
.ctl{width:44px;height:44px;border-radius:50%;background:var(--panel2);border:1px solid var(--line);
  display:grid;place-items:center;font-size:19px;line-height:1}
.ctl:hover{background:var(--hover)}
.ctl.off{background:var(--offbg);border-color:var(--offline);color:var(--offink)}
.ctl.on{background:var(--onbg);border-color:var(--online);color:var(--acc)}
.ctl.leave{width:auto;padding:0 16px;border-radius:21px;background:var(--offbg);border-color:var(--offline);color:var(--offink);font-size:13px}
/* [stated] "remove the text in bottom left entirely doesnt need to show the code its
   in url", and the engine name likewise: "we don't need to say transcribing nova 2 …
   there should just be link".

   These lived under @media (max-width:900px) because the report came from a phone, and
   that was the wrong reading of "entirely" — on a desktop both were still sitting in
   the corner, which read later as a rollback of a fix that had never applied there. The
   address bar shows the code on every screen, so the argument does not depend on width.

   Two things stay, and neither is text: the share control, which is the button that
   copies an invite and the only thing in that pill anybody presses; and the listening
   dot, which says whether transcription is running. Hovering the dot still names the
   engine, for whoever actually wants to know. */
.room .rc{display:none}
.asrtag{display:none}

.room{font-family:var(--mono);font-size:12px;color:var(--mid);background:var(--panel2);
  border:1px solid var(--line);border-radius:7px;padding:4px 8px;
  display:inline-flex;align-items:center;gap:7px}
/* Now that the code is gone at every width, this pill is an icon button and nothing
   else — so it is sized like one instead of like a label that happens to have a glyph
   on the end. 13px in a 31px box was the leftover shape of the text that used to sit
   beside it. */
.room{width:34px;height:34px;padding:0;display:grid;place-items:center;border-radius:10px}
.room .shareicon{width:17px;height:17px;flex:none;opacity:.75;transition:opacity .15s}
button.room:hover .shareicon{opacity:1;color:var(--acc2)}
.dot{width:8px;height:8px;border-radius:50%;background:var(--dim)}
.dot.live{background:var(--good);box-shadow:0 0 8px var(--good)}
.muted{color:var(--dim);font-size:12px}
.ghost{color:var(--mid);font-size:13px;padding:6px 10px;border-radius:8px}
.ghost:hover{background:var(--panel2)}

/* ───────── rail ───────── */
.rail-top{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;border-bottom:1px solid var(--line)}
.phases{display:flex;gap:4px;font-size:11px;text-transform:uppercase;letter-spacing:.07em}
/* Same trap as .sheet: a display rule beats the [hidden] attribute, so the QuickAlign
   stepper stayed on screen in every other mode. Any element hidden by attribute needs
   this said explicitly. */
.phases[hidden]{display:none}
.phases button{padding:5px 9px;border-radius:7px;color:var(--dim);background:transparent;
  font-size:inherit;letter-spacing:inherit;text-transform:inherit;font-family:inherit}
.phases button.done{color:var(--mid)}
.phases button.now{color:#fff;background:var(--grad);font-weight:700}
.phases button.can{cursor:pointer}
.phases button.can:hover{background:var(--panel2);color:var(--ink)}
.phases button:disabled{cursor:default}
.rail-body{flex:1;overflow-y:auto;padding:14px;display:flex;flex-direction:column;gap:14px}
.rail-body::-webkit-scrollbar{width:8px}
.rail-body::-webkit-scrollbar-thumb{background:#232a35;border-radius:8px}

.card{background:var(--panel2);border:1px solid var(--line);border-radius:var(--r);padding:13px}
.card h3{margin:0 0 10px;font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:var(--dim);font-weight:650}
.card h3 .n{color:var(--mid);font-weight:500;text-transform:none;letter-spacing:0}
.card.offer{border-color:var(--acc2);background:linear-gradient(160deg,var(--sunk2),var(--sunk))}
.card.hero{border-color:var(--edge)}
.empty{color:var(--dim);font-size:13px;line-height:1.55}

.meter{height:6px;background:var(--field);border-radius:4px;overflow:hidden;margin:8px 0 6px}
.meter i{display:block;height:100%;background:var(--grad);transition:width .6s}
.meter-row{display:flex;justify-content:space-between;font-size:11px;color:var(--dim)}

.item{padding:7px 0;border-bottom:1px solid var(--hair);font-size:13.5px;line-height:1.5}
.item:last-child{border-bottom:0}
.item .q{display:block;margin-top:4px;color:var(--mid);font-size:12px;border-left:2px solid var(--edge);padding-left:8px}
.item .q b{color:var(--dim);font-weight:500}
.item .flag{font-size:10px;text-transform:uppercase;letter-spacing:.06em;color:var(--warn);
  border:1px solid #4a3a22;border-radius:5px;padding:1px 5px;margin-left:6px;white-space:nowrap}
.item .flag.human{color:var(--acc);border-color:var(--online)}

.who{display:flex;align-items:center;gap:8px;padding:6px 0;border-bottom:1px solid var(--hair);font-size:13px}
.who:last-child{border-bottom:0}
.who .nm{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.who select{background:var(--field);border:1px solid var(--line);border-radius:7px;padding:4px 6px;font-size:12px}
.who .vv{font-size:10px;color:var(--dim);text-transform:uppercase;letter-spacing:.05em;width:64px;text-align:right}

textarea,input.f,select.f{width:100%;background:var(--field);border:1px solid var(--line);border-radius:9px;
  padding:9px 11px;outline:none;resize:vertical;font-size:13.5px;line-height:1.5}
textarea:focus,input.f:focus,select.f:focus{border-color:var(--acc2)}
label.lbl{display:block;font-size:11px;text-transform:uppercase;letter-spacing:.07em;color:var(--dim);margin:10px 0 5px}
.btnrow{display:flex;gap:8px;margin-top:10px;flex-wrap:wrap}
/* The format the room's live pictures are drawn in — pressed, and it stays pressed. */
.drawkinds .btn.on{background:var(--acc);border-color:var(--acc);color:#fff;font-weight:600}
.drawlive b{color:var(--ink);font-weight:600}
/* color is set, not inherited. Without it a .btn takes whatever colour its container
   happens to have — which is fine inside a panel and unreadable inside an overlay that
   sets a light colour for its own text. "Take down" and "Close for me" came out white
   on white in light mode for exactly this reason. A control's legibility must not
   depend on where somebody nests it. */
.btn{background:var(--panel2);color:var(--ink);border:1px solid var(--line);border-radius:9px;padding:9px 13px;font-size:13px}
.btn:hover{background:var(--hover)}
.btn.go{background:var(--grad);color:#fff;font-weight:600;border:0}
.btn.quiet{color:var(--mid)}
.btn:disabled{opacity:.45;cursor:default}
.btn.wide{flex:1}

.tabs{display:flex;gap:4px;margin-bottom:10px;flex-wrap:wrap}
.tabs button{font-size:12px;padding:6px 10px;border-radius:8px;background:var(--field);border:1px solid var(--line);color:var(--mid)}
.tabs button.on{background:var(--grad);color:#fff;border-color:transparent;font-weight:600}
.tabs button .b{opacity:.7;margin-left:4px}

.proposal{white-space:pre-wrap;font-size:14.5px;line-height:1.62}
.round{font-family:var(--mono);font-size:11px;color:var(--acc2);border:1px solid var(--edge2);border-radius:6px;padding:2px 7px}

.probe{padding:8px 0;border-bottom:1px solid var(--hair);font-size:13.5px;line-height:1.5}
.probe:last-child{border-bottom:0}
.probe .nm{color:var(--acc2);font-weight:600}
.probe .c{font-size:10px;text-transform:uppercase;letter-spacing:.06em;color:var(--dim);margin-left:6px}

.tal{display:grid;grid-template-columns:repeat(4,1fr);gap:6px;margin:10px 0}
.tal div{background:var(--field);border:1px solid var(--line);border-radius:9px;padding:8px;text-align:center}
.tal b{display:block;font-size:19px;line-height:1.2}
.tal span{font-size:10px;color:var(--dim);text-transform:uppercase;letter-spacing:.05em}
.verdict{border-radius:9px;padding:10px 12px;font-size:13.5px;line-height:1.5;margin-top:4px}
.verdict.yes{background:#07281f;border:1px solid #1c5c48;color:#b8f5de}
.verdict.no{background:#2c1a1e;border:1px solid #5b2b31;color:#f8cfcf}

.commit-row{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:8px}
.commit-row button{flex:1 1 auto;font-size:12px;padding:8px 6px;border-radius:8px;background:var(--field);
  border:1px solid var(--line);color:var(--mid);white-space:nowrap}
.commit-row button.on{border-color:var(--good);color:var(--good);background:#08251c}
.commit-row button.blockon{border-color:var(--bad);color:var(--bad);background:#26161a}

.act-row{display:flex;gap:8px;padding:8px 0;border-bottom:1px solid var(--hair);font-size:13.5px}
.act-row:last-child{border-bottom:0}
.act-row .own{color:var(--acc2);font-size:12px;white-space:nowrap}

#toasts{position:fixed;left:50%;transform:translateX(-50%);top:14px;z-index:60;display:flex;flex-direction:column;gap:8px;align-items:center}
.toast{background:var(--panel2);border:1px solid var(--line);border-radius:10px;padding:9px 14px;font-size:13px;
  box-shadow:0 8px 30px rgba(0,0,0,.5)}
.toast.warn{border-color:#5b4a2b;color:#ffdca8}
.toast .toastlink{display:inline-block;margin-left:10px;color:#ffe9b0;font-weight:600;text-decoration:underline;text-underline-offset:2px}
/* The gold star: one glyph, the same everywhere a name is written. */
.star{display:inline-block;color:#F5C542;font-size:.95em;line-height:1;margin-left:4px;vertical-align:-1px;
  text-shadow:0 0 6px rgba(245,197,66,.35)}
.tile .chip .star{margin-left:0;font-size:12px}
.spin{display:inline-block;width:11px;height:11px;border:2px solid var(--edge);border-top-color:var(--acc2);
  border-radius:50%;animation:sp .8s linear infinite;vertical-align:-1px;margin-right:6px}
@keyframes sp{to{transform:rotate(360deg)}}

@media (max-width:900px){
  #app{grid-template-columns:1fr;grid-template-rows:1fr 300px 60px;
    grid-template-areas:"stage" "rail" "bar"}
  #rail{border-left:0;border-top:1px solid var(--line)}
  #app.norail{grid-template-rows:1fr 0 60px}
  .arc{grid-template-columns:1fr 1fr}
}

/* ───────── the coach ─────────
   One instruction at a time, computed from what the room actually is. It is the
   first thing in the rail because "what do I do now" is the question a person in a
   new process is always asking, and answering it once at the door is not enough. */
.coach{background:linear-gradient(160deg,var(--sunk2),var(--sunk));border:1px solid var(--edge2);
  border-radius:var(--r);padding:14px}
.coach .do{font-size:15px;line-height:1.45;font-weight:600}
.coach .sub{margin-top:7px;color:var(--mid);font-size:13px;line-height:1.55}
.coach .ask{margin-top:10px;font-size:15px;line-height:1.5;color:var(--ink);
  border-left:2px solid var(--blue);padding-left:10px}
.coach .btnrow{margin-top:12px}
.rail-tools{display:flex;gap:6px;align-items:stretch}
/* One height for everything in this row — a 28px circle beside a taller Close pill
   reads as two different controls that happen to be neighbours. */
.rail-tools > button, .rail-tools .ghost{height:34px;box-sizing:border-box;
  display:inline-flex;align-items:center;justify-content:center}
#guideBtn, #themeBtn{width:34px;padding:0;border:1px solid var(--line);border-radius:9px;font-size:13px}

.cstep{display:flex;gap:4px;margin-bottom:10px}
.cstep button{flex:1;min-width:0;font-size:10px;letter-spacing:-.2px;padding:7px 2px;border-radius:8px;
  background:var(--field);border:1px solid var(--line);color:var(--dim);text-align:center;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cstep button .num{display:block;font-size:9px;opacity:.7}
.cstep button.now{background:var(--grad);color:#fff;border-color:transparent;font-weight:700}
.cstep button.done{color:var(--good);border-color:#1c5c48}

.invite{display:flex;gap:6px;margin-top:10px}
.invite input{flex:1;background:var(--field);border:1px solid var(--line);border-radius:8px;
  padding:8px 10px;font-size:12px;font-family:var(--mono);color:var(--mid);min-width:0}

/* ───────── how this works ───────── */
.sheet{position:fixed;inset:0;z-index:70;background:rgba(6,8,12,.72);backdrop-filter:blur(4px);
  display:grid;place-items:center;padding:20px}
/* `display:grid` beats the [hidden] attribute, and a full-screen invisible overlay
   that still eats clicks is indistinguishable from the app being frozen. */
.sheet[hidden]{display:none}
.sheet-card{position:relative;width:min(720px,94vw);max-height:86vh;overflow-y:auto;
  background:var(--panel);border:1px solid var(--line);border-radius:16px;padding:30px 34px;
  /* A scroll container with a hard bottom edge reads as a dialog that was cut off
     — the taste pass called it "no bottom". A visible scrollbar says there is more. */
  scrollbar-width:thin;scrollbar-color:var(--line) transparent;scrollbar-gutter:stable}
.sheet-x{position:absolute;right:14px;top:10px;font-size:24px;color:var(--dim);line-height:1}
.sheet-x:hover{color:var(--ink)}
.sheet-body h2{margin:0 0 4px;font-size:22px;letter-spacing:-.01em}
.sheet-body h3{margin:26px 0 8px;font-size:12px;text-transform:uppercase;letter-spacing:.08em;color:var(--acc2)}
.sheet-body p{margin:0 0 10px;color:var(--mid);font-size:14px;line-height:1.65}
.sheet-body p.lead{color:var(--ink)}
.sheet-body ol,.sheet-body ul{margin:0 0 10px;padding-left:20px;color:var(--mid);font-size:14px;line-height:1.65}
.sheet-body li{margin-bottom:8px}
.sheet-body b{color:var(--ink)}
.sheet-body .q{display:block;margin-top:3px;color:var(--ink);border-left:2px solid var(--acc);padding-left:9px}
.sheet-body .src{margin-top:26px;padding-top:14px;border-top:1px solid var(--line);font-size:12px;color:var(--dim)}

/* ───────── door: mode picker ───────── */
.gate-inner.wide{width:min(700px,94vw)}
.gate-row{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.modepick{display:grid;grid-template-columns:repeat(2,1fr);gap:8px;margin:14px 0 4px;text-align:left}
.modepick button{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:12px 13px}
.modepick button:hover{border-color:#31415c}
.modepick button.on{border-color:var(--acc2);background:linear-gradient(160deg,var(--sunk2),var(--sunk))}
.modepick .mh{display:flex;align-items:center;gap:8px;font-weight:650;font-size:14px}
.modepick .mt{font-size:9px;text-transform:uppercase;letter-spacing:.08em;color:var(--dim);
  border:1px solid var(--line);border-radius:5px;padding:1px 5px}
.modepick .mb{margin-top:5px;color:var(--mid);font-size:12px;line-height:1.5}
.modepick button.on .mt{color:var(--acc2);border-color:var(--edge2)}

/* ───────── rail: mode bar ───────── */
/* The tab strip SCROLLS inside its own box; it never overflows onto its neighbour.
   `min-width:0` lets the strip shrink, but its buttons are nowrap and do not, so the
   content simply painted outside the box — and a button that paints outside its box
   still takes clicks. Adding a fifth tab put Transcript exactly on top of the rail's
   "?" and Chat on top of Close, so neither could be pressed at any width: the rail is
   a fixed 400px and five tabs measure 360 in 270. Same family as the `1fr` track that
   has cost this codebase 874px of sideways scroll and then 47px twice — a child that
   cannot shrink has to be given somewhere to go. */
.tabs-top{display:flex;gap:2px;min-width:0;flex:1 1 auto;overflow-x:auto;
  scrollbar-width:none;-ms-overflow-style:none;
  /* the last tab fades out rather than being cut, so there is visibly more to the right */
  -webkit-mask-image:linear-gradient(90deg,#000 calc(100% - 18px),transparent);
  mask-image:linear-gradient(90deg,#000 calc(100% - 18px),transparent)}
.tabs-top::-webkit-scrollbar{display:none}
.tabs-top button{position:relative;font-size:12.5px;padding:7px 10px;border-radius:9px;color:var(--dim);white-space:nowrap;flex:0 0 auto}
.tabs-top button:hover{background:var(--panel2);color:var(--mid)}
.tabs-top button.on{background:var(--panel2);color:var(--ink);font-weight:600}
.tabs-top .unread{top:4px;right:4px}
/* and the controls beside it are never squeezed to make room for tabs */
.rail-tools{flex:0 0 auto}
/* Five tabs and two controls do not fit across a 400px rail, and the scroll that
   hid the overflow read as a cut — the taste pass saw "ode" and "Transcri" on
   every room screen. Whenever the rail is narrower than its header wants, the
   header takes two rows: Close and ? on top, the tabs beneath with the full width,
   the same arrangement the phone already uses. Measured on the rail, not the
   window, so a wider rail one day gets its single row back on its own. */
#rail{container-type:inline-size;container-name:rail}
@container rail (max-width:600px){
  .rail-top{display:grid;grid-template-columns:auto 1fr auto;grid-template-areas:'close . help' 'tabs tabs tabs';row-gap:8px;align-items:center;padding:10px 12px 8px}
  .rail-tools{display:contents}
  #railClose{grid-area:close;order:0;margin-right:0}
  #guideBtn{grid-area:help;order:0}
  .tabs-top{grid-area:tabs;overflow-x:visible;gap:4px;justify-content:space-between;-webkit-mask-image:none;mask-image:none}
  /* Natural widths plus an equal share of what is left — `1 1 0` split the row
     evenly and cut "Transcript" to "Transcr…" beside a "Chat" with room to spare. */
  .tabs-top button{flex:1 1 auto;min-width:0;padding:8px 4px;font-size:12px;text-align:center;overflow:hidden;text-overflow:ellipsis}
}

/* One control, showing the mode you are in — not four buttons and four tooltips. */
.modeline{position:relative;padding:10px 12px 0}
.modeBtn{display:flex;align-items:center;gap:9px;width:100%;
  background:var(--panel2);border:1px solid var(--line);border-radius:10px;padding:9px 12px;font-size:13.5px;
  transition:border-color .15s,background .15s}
.modeBtn .mk{font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--dim);
  border-right:1px solid var(--line);padding-right:9px}
.modeBtn #modeNow{flex:1;text-align:left;font-weight:600}
.modeBtn .chev{color:var(--blue);flex:none;transition:transform .18s}
.modeBtn:hover:not(:disabled){border-color:var(--blue);background:#131a3e}
.modeBtn[aria-expanded=true] .chev{transform:rotate(180deg)}
.modeBtn:disabled{opacity:.6;cursor:default}
.modeBtn:disabled .chev{display:none}
.modemenu{position:absolute;left:12px;right:12px;top:calc(100% - 2px);z-index:12;
  background:var(--panel2);border:1px solid var(--line);border-radius:12px;padding:6px;
  box-shadow:0 24px 60px rgba(3,10,50,.7)}
.modemenu[hidden]{display:none}
.modemenu button{display:block;width:100%;text-align:left;padding:9px 10px;border-radius:9px}
.modemenu button:hover{background:var(--panel3)}
.modemenu button.on{background:rgba(7,148,252,.12)}
.modemenu b{display:block;font-size:13.5px}
.modemenu span{display:block;color:var(--dim);font-size:11.5px;line-height:1.5;margin-top:2px}

#notesPane,#txPane,#chatPane{flex:1;display:flex;flex-direction:column;min-height:0}
#notesPane[hidden],#txPane[hidden],#chatPane[hidden]{display:none}
.tx-head{display:flex;align-items:center;justify-content:space-between;padding:9px 12px;
  border-bottom:1px solid var(--line);font-size:12px}
.tx-head .ghost.on{color:var(--blue-ink)}
.tx-body{gap:0}
.txline{padding:7px 0;border-bottom:1px solid rgba(28,35,80,.55);font-size:13.5px;line-height:1.6}
.txline:last-child{border-bottom:0}
.txline b{color:var(--blue-ink);font-weight:600}
.txline.ai b{color:var(--acc2)}
.txline i{color:var(--dim);font-style:normal;font-family:var(--mono);font-size:10.5px;margin-left:7px}
.txline.live{opacity:.6}
#phases{padding:8px 12px;border-bottom:1px solid var(--line)}

.rail-ask{display:flex;gap:6px;padding:10px 12px;border-top:1px solid var(--line);background:var(--panel)}
.rail-ask input{flex:1;min-width:0;background:var(--field);border:1px solid var(--line);border-radius:9px;
  padding:9px 11px;font-size:13px;outline:none}
.rail-ask input:focus{border-color:var(--acc2)}

/* ───────── recording ───────── */
/* The meeting's own red dot and the clip's stack in one corner: the meeting is
   recorded without anyone pressing anything, so its dot is the only place that
   fact is shown, and a clip taken during it sits under it rather than on it. */
.recdots{position:absolute;left:20px;top:20px;display:flex;flex-direction:column;align-items:flex-start;gap:6px;pointer-events:none}
.recdots .recdot{pointer-events:auto}
.recdot{display:flex;align-items:center;gap:8px;
  background:rgba(8,11,16,.82);border:1px solid #5b2b31;border-radius:9px;padding:6px 11px;
  font-size:12px;letter-spacing:.06em;backdrop-filter:blur(6px)}
.recdot i{width:9px;height:9px;border-radius:50%;background:#ef4444;animation:blink 1.6s infinite}
.recdot b{font-family:var(--mono);color:#AEB9D6;font-weight:500}
@keyframes blink{0%,100%{opacity:1}50%{opacity:.25}}
.ctl.rec{background:#3a1f24;border-color:#5b2b31;color:#ff9a9a}

/* ───────── mode content ───────── */
.topic{border:1px solid var(--line);border-radius:10px;padding:10px 12px;margin-bottom:8px;background:var(--field)}
.topic.now{border-color:var(--acc2)}
.topic.covered{border-color:#1c5c48}
.topic h4{margin:0;font-size:13.5px;display:flex;align-items:center;gap:8px;line-height:1.4}
.topic .st{font-size:9px;text-transform:uppercase;letter-spacing:.07em;padding:2px 6px;border-radius:5px;
  border:1px solid var(--line);color:var(--dim);white-space:nowrap}
.topic.covered .st{color:var(--good);border-color:#1c5c48}
.topic.now .st{color:var(--acc2);border-color:var(--edge2)}

.shots{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.shot{border:1px solid var(--line);border-radius:10px;overflow:hidden;background:var(--field)}
.shot img{width:100%;display:block;aspect-ratio:16/9;object-fit:cover;cursor:zoom-in}
.shot .cap{padding:7px 9px;font-size:11.5px;color:var(--mid);line-height:1.45}
.shot .cap b{color:var(--ink);font-weight:600}
/* [stated, 2026-10-23] "A LARGER POOL OF THOUGHT INFOGRAPHIC WHICH IT CAN PUT A THICKER
   BORDER ON TO DISPLAY IT WAS MORE OF THE CONVERSATION". */
.shot.wide{grid-column:1/-1;border:3px solid transparent;border-radius:12px;position:relative;
  background:linear-gradient(var(--field),var(--field)) padding-box,linear-gradient(135deg,#0794FC,#5B2EF2,#F5C542) border-box}
.shot.wide .widetag{position:absolute;top:8px;left:8px;z-index:1;font-size:10.5px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
  color:#fff;background:rgba(5,8,23,.72);border-radius:99px;padding:3px 9px}

.ask-row{padding:9px 0;border-bottom:1px solid var(--hair);font-size:13.5px;line-height:1.55}
.ask-row:last-child{border-bottom:0}
.ask-row .who{color:var(--acc2);font-weight:600;font-size:12px}
.ask-row .ans{margin-top:4px}
.ask-row .beyond{font-size:10px;text-transform:uppercase;letter-spacing:.06em;color:var(--warn);
  border:1px solid #4a3a22;border-radius:5px;padding:1px 5px;margin-left:6px}

.lightbox{position:fixed;inset:0;z-index:80;background:rgba(6,8,12,.9);display:grid;place-items:center;padding:24px}
.lightbox[hidden]{display:none}
.lightbox img{max-width:96vw;max-height:88vh;border-radius:12px}
.lightbox p{position:absolute;bottom:18px;left:50%;transform:translateX(-50%);color:var(--mid);font-size:13px;
  background:rgba(8,11,16,.8);padding:8px 14px;border-radius:8px;max-width:80vw;text-align:center}

@media (max-width:900px){ .modepick{grid-template-columns:1fr} .gate-row{grid-template-columns:1fr} }

.tag2{margin:-6px 0 22px;color:var(--dim);font-size:13px;line-height:1.6;max-width:520px;
  margin-left:auto;margin-right:auto}

/* ───────── door: start or join ───────── */
#gateForm{display:grid;gap:8px}
.codechip{display:flex;justify-content:center;margin:2px 0 2px}
.codechip span{font-family:var(--mono);font-size:20px;letter-spacing:.08em;color:var(--blue);
  background:rgba(7,148,252,.08);border:1px solid rgba(7,148,252,.35);border-radius:12px;padding:11px 18px}
.gerr{color:#f8cfcf;background:#2c1a1e;border:1px solid #5b2b31;border-radius:10px;
  padding:10px 12px;font-size:13px;margin:2px 0 0;line-height:1.5}
.gerr[hidden]{display:none}

/* ───────── presenting ───────── */
#stage{display:flex;flex-direction:column;gap:10px}
/* #spotlight holds the screens being shared — a pane each (app.js renderSpotlight) — and
   takes the stage's room; each pane is a framed screen. Two on show sit side by side, as
   wide as the line between them was dragged (--scrL / --scrR). */
.spotlight{position:relative;flex:1;min-height:0;min-width:0;display:grid;gap:10px;
  grid-template-columns:minmax(0,1fr);grid-template-rows:minmax(0,1fr)}
.spotlight.two{grid-template-columns:minmax(0,var(--scrL,1fr)) minmax(0,var(--scrR,1fr))}
.spotlight[hidden]{display:none}
.spotlight .scr{position:relative;min-width:0;min-height:0;border-radius:var(--r);overflow:hidden;
  background:#05070a;border:1px solid var(--acc2)}
.spotlight .scr[hidden]{display:none}
.spotlight .scr > video{width:100%;height:100%;object-fit:contain;background:#05070a;display:block}
.spotlight.two .scr{cursor:zoom-in}
/* More screens than room: a row of their names above them — a row of its own, so it
   covers neither the presenter's name nor their face — and the one pressed is shown. */
.spotlight.picking{grid-template-rows:auto minmax(0,1fr)}
.scrpick{order:-1;grid-column:1 / -1;justify-self:center;position:relative;z-index:4;display:flex;align-items:center;
  gap:4px;max-width:100%;overflow-x:auto;scrollbar-width:none;padding:4px;border-radius:999px;
  background:rgba(8,11,16,.82);border:1px solid rgba(255,255,255,.14)}
.scrpick[hidden]{display:none}
.scrpick-n{color:#c9d2ec;font-size:11.5px;padding:0 6px 0 8px;white-space:nowrap}
.scrchip{flex:0 0 auto;border:0;border-radius:999px;padding:5px 11px;font-size:12px;font-weight:600;
  background:transparent;color:#e9edff;white-space:nowrap;cursor:pointer}
.scrchip:hover{background:rgba(255,255,255,.1)}
.scrchip.on{background:linear-gradient(90deg,#0794FC,#5B2EF2);color:#fff}
.spotbar{position:absolute;z-index:3;left:12px;top:12px;display:flex;gap:10px;align-items:center;
  background:rgba(8,11,16,.82);border:1px solid var(--line);border-radius:9px;padding:6px 11px;
  font-size:12.5px;backdrop-filter:blur(6px)}
.spotbar .btn{padding:5px 10px;font-size:12px}
/* A shared screen or a picture put in front of everyone: the frame is theirs and the
   faces are a strip. ONE set of rules for both, so the picture can never again get a
   layout of its own that forgets the picture-in-picture. */
#app.strip #grid{flex:none;height:132px;align-content:stretch}
#app.strip #grid .tile{min-height:0}
#app.strip #grid .chip{font-size:11px;padding:3px 7px}
/* Both at once — somebody presenting put a picture up as well: the picture gets the
   room and the shared screen keeps a strip of its own above it, still playing. */
#app.presenting.imgstage .spotlight{flex:0 0 var(--striph);min-height:0}
#app.presenting.imgstage .spotbar,#app.presenting.imgstage .spotface{display:none}
/* A face pinned over the stage holder: the face takes the room, the screen or picture
   is a thumbnail strip above it — tap the thumbnail to get it back. */
#app.pinover .spotlight,#app.pinover .imgspot{flex:0 0 var(--striph);min-height:0;cursor:pointer}
#app.pinover .spotbar,#app.pinover .spotface,#app.pinover .imgspot .isp-bar{display:none}
#app.pinover .imgspot{gap:0;padding:0}
#app.pinover .imgspot .isp-frame{cursor:pointer}
#app.pinover .imgspot img{border-radius:8px}

/* ───────── chat ───────── */
.chat-body{gap:10px}
.cm{font-size:13.5px;line-height:1.55}
.cm .nm{color:var(--acc2);font-weight:600;font-size:12px;margin-right:6px}
.cm .tm{color:var(--dim);font-size:11px;font-family:var(--mono)}
.cm.sys{color:var(--mid);font-size:12.5px;font-style:italic}
.cm a{color:var(--acc);word-break:break-all}
.clip{background:var(--panel2);border:1px solid rgba(7,148,252,.4);border-radius:12px;padding:11px 12px}
.clip b{display:block;font-size:13px;margin-bottom:2px;font-style:normal}
.clip .row{display:flex;gap:6px;margin-top:9px}
.clip .row a,.clip .row button{font-size:12px;padding:6px 10px;border-radius:8px;
  background:var(--field);border:1px solid var(--line);color:var(--mid);text-decoration:none}
.clip .row a.go{background:var(--grad);color:#fff;border:0;font-weight:600}
.chat-send{display:flex;align-items:center;gap:6px;padding:10px 12px;border-top:1px solid var(--line)}
.chat-send input{flex:1;min-width:0;background:var(--field);border:1px solid var(--line);border-radius:9px;
  padding:9px 11px;font-size:13px;outline:none}
.chat-send input:focus{border-color:var(--acc2)}

.ctl.wide-ctl{display:flex;align-items:center;justify-content:center;width:auto;height:42px;
  padding:0 16px;border-radius:21px;gap:8px;white-space:nowrap;line-height:1}
.ctl.wide-ctl span{font-size:12.5px;font-weight:500}
@media (max-width:1100px){ .ctl.wide-ctl span{display:none} .ctl.wide-ctl{width:42px;padding:0} }
.ctl{position:relative}
.unread{position:absolute;top:3px;right:2px;min-width:16px;height:16px;padding:0 4px;
  border-radius:9px;background:#E5484D;color:#fff;font-family:var(--mono);font-size:10px;
  font-weight:600;line-height:16px;text-align:center;font-style:normal;
  box-shadow:0 0 0 2px var(--panel)}
/* The rail is closed on a phone, so the button that opens it wears the mark too. */
.hasunread{position:relative}
.hasunread::after{content:'';position:absolute;top:-3px;right:-3px;width:9px;height:9px;
  border-radius:50%;background:#E5484D;box-shadow:0 0 0 2px var(--panel)}

/* ───────── who is who, and where they are looking ─────────
   One hue per person, the same on every machine because it is derived from their id.
   It runs along the top of their tile rather than around it: a full border competes
   with the speaking ring, and the ring is the more urgent of the two. */
.tile::before{content:'';position:absolute;left:0;right:0;top:0;height:2px;z-index:2;
  background:var(--who, transparent);opacity:.85;border-radius:var(--r) var(--r) 0 0}
.tile.me::before{opacity:.55}
.whereat{position:absolute;top:8px;left:8px;z-index:3;display:inline-flex;align-items:center;
  gap:5px;padding:3px 8px;border-radius:999px;font-size:10.5px;letter-spacing:.01em;
  color:#EAF0FF;background:rgba(8,11,16,.72);backdrop-filter:blur(6px);
  border:1px solid rgba(255,255,255,.12)}
.whereat::before{content:'';width:5px;height:5px;border-radius:50%;background:var(--who,#8aa);
  box-shadow:0 0 6px var(--who,#8aa)}
button.room{cursor:pointer}
button.room:hover{border-color:var(--acc2);color:var(--ink)}

/* ───────── icons in the bar ─────────
   Mic and camera stay as the emoji Jack liked. Everything else is line art at a size
   we control, which is also the fix for the settings glyph rendering oversized —
   an emoji is drawn at whatever size the platform font decides. */
.ctl.icon svg{width:21px;height:21px;display:block}
.ctl.icon{font-size:0}
#setBtn svg{width:19px;height:19px}
.recdotic{width:11px;height:11px;fill:#ff6b7a;display:block}
#recBtn.rec .recdotic{animation:recpulse 1.2s ease-in-out infinite}
@keyframes recpulse{0%,100%{opacity:1}50%{opacity:.3}}

/* ───────── what a control actually does, on hover ─────────
   The native `title` takes about a second to appear, cannot be styled, and on a
   crowded bar it arrives as a grey box over somebody's face. This is the same
   information, faster, above the bar, and unable to intercept a click. */
[data-tip]{position:relative}
[data-tip]::after{
  content:attr(data-tip);position:absolute;bottom:calc(100% + 10px);left:50%;
  transform:translateX(-50%) translateY(4px);
  /* A tooltip is a dark chip in BOTH themes — same rule as anything painted over
     video. var(--ink) here was near-black in light mode: dark text on a dark chip,
     invisible exactly when somebody has just switched theme and is reading labels. */
  background:#0B0F22;color:#F1F4FF;border:1px solid rgba(255,255,255,.16);
  border-radius:9px;padding:7px 11px;font-size:12.5px;line-height:1.35;
  font-family:'Inter',system-ui,sans-serif;font-weight:450;letter-spacing:0;
  white-space:nowrap;max-width:min(74vw,340px);overflow:hidden;text-overflow:ellipsis;
  pointer-events:none;opacity:0;z-index:40;
  box-shadow:0 12px 30px -12px rgba(0,0,0,.85);
  transition:opacity .12s ease,transform .12s ease;transition-delay:.28s;
}
[data-tip]::before{
  content:'';position:absolute;bottom:calc(100% + 5px);left:50%;
  transform:translateX(-50%) translateY(4px);
  border:5px solid transparent;border-top-color:var(--line);
  pointer-events:none;opacity:0;z-index:41;
  transition:opacity .12s ease,transform .12s ease;transition-delay:.28s;
}
[data-tip]:hover::after,[data-tip]:focus-visible::after,
[data-tip]:hover::before,[data-tip]:focus-visible::before{
  opacity:1;transform:translateX(-50%) translateY(0);
}
/* The controls at the edges would push their label off-screen, so they hug the edge. */
#leaveBtn[data-tip]::after{left:auto;right:0;transform:translateX(0) translateY(4px)}
#leaveBtn[data-tip]:hover::after{transform:translateX(0) translateY(0)}
#leaveBtn[data-tip]::before,#leaveBtn[data-tip]::after{left:auto;right:14px}
.bar-left [data-tip]::after{left:0;transform:translateX(0) translateY(4px)}
.bar-left [data-tip]:hover::after{transform:translateX(0) translateY(0)}
.bar-left [data-tip]::before{left:22px}
.bar-right [data-tip]::after{left:auto;right:0;transform:translateX(0) translateY(4px)}
.bar-right [data-tip]:hover::after{transform:translateX(0) translateY(0)}
.bar-right [data-tip]::before{left:auto;right:30px}
/* A finger has no hover. Showing these on tap would just cover the thing you tapped. */
@media (hover:none){ [data-tip]::after,[data-tip]::before{display:none} }

.btn.go.wide{display:block;width:100%;text-align:center}
#shareCopy.done{background:var(--good);border-color:var(--good);color:#04241b}
#shareCopy.showing{font-family:var(--mono);font-size:12px;word-break:break-all;white-space:normal}


/* ═══════════════════════════ the landing page ═══════════════════════════
   Dark-first, the brand's own gradient used as light rather than as paint, and
   the faceted mark left to be itself instead of tiled across everything. */

.site{scroll-behavior:smooth}
.display{font-family:var(--display);font-weight:700;letter-spacing:-.035em;line-height:1.03;
  font-size:clamp(34px,5vw,68px);margin:0}
.display.sm{font-size:clamp(34px,4.4vw,58px)}
.h2{font-family:var(--display);font-weight:600;letter-spacing:-.025em;
  font-size:clamp(28px,3.4vw,44px);line-height:1.1;margin:0 0 14px}
.lead{color:var(--mid);font-size:clamp(15px,1.35vw,18px);line-height:1.7;margin:0 0 14px;max-width:62ch}
.lead em{color:var(--ink);font-style:normal}

.nav{position:sticky;top:0;z-index:20;display:flex;align-items:center;justify-content:space-between;
  padding:16px clamp(18px,4vw,52px);backdrop-filter:blur(14px);
  background:linear-gradient(180deg,rgba(5,8,23,.92),rgba(5,8,23,.55));border-bottom:1px solid rgba(28,35,80,.6)}
.brand-lockup{display:flex;align-items:center;gap:11px;text-decoration:none}
.brand-lockup img{height:30px;width:auto;display:block}
.brand-lockup .wm{height:13px;opacity:.95}
.nav-links{display:flex;gap:clamp(12px,2vw,26px);align-items:center}
.nav-links a{color:var(--mid);text-decoration:none;font-size:13.5px;font-weight:500}
.nav-links a:hover{color:var(--ink)}
@media (max-width:760px){ .nav-links a:not(:last-child){display:none} }

.hero{position:relative;padding:clamp(30px,5vh,64px) clamp(18px,4vw,52px) clamp(34px,5vh,64px);
  overflow:hidden;min-height:calc(100svh - 64px);display:grid;align-items:center}
.ambient{position:absolute;inset:-20% -10% auto -10%;height:150%;pointer-events:none;
  background:radial-gradient(circle at 74% 12%,rgba(91,46,242,.34),transparent 44%),
             radial-gradient(circle at 8% 78%,rgba(7,148,252,.24),transparent 40%)}
.hero-inner{position:relative;max-width:1080px;margin:0 auto;text-align:center}
.eyebrow{font-size:11.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--blue);
  font-weight:600;margin:0 0 14px}
.hero .sub{color:var(--mid);font-size:clamp(14.5px,1.25vw,17px);line-height:1.6;
  max-width:58ch;margin:16px auto 0}

.startcard{max-width:410px;margin:26px auto 0;display:grid;gap:9px;text-align:left;
  background:rgba(15,20,48,.72);border:1px solid var(--line);border-radius:var(--r);
  padding:18px;box-shadow:0 30px 90px rgba(3,10,50,.55);backdrop-filter:blur(10px)}
.startcard input[type=text],.startcard input#gname{width:100%}
.startcard #gname{background:var(--deepbg);border:1px solid var(--line);border-radius:12px;
  padding:13px 15px;outline:none;font-size:16px;color:var(--ink)}
.startcard #gname:focus{border-color:var(--blue);box-shadow:0 0 0 3px rgba(7,148,252,.16)}
.cta{background:var(--grad);color:#fff;font-weight:600;font-size:16px;border-radius:12px;
  padding:14px;border:0;box-shadow:0 12px 34px rgba(7,85,235,.4);font-family:var(--display);letter-spacing:-.01em}
.cta:hover{filter:brightness(1.08)}
.cta:disabled{opacity:.55}
.startnote{color:var(--dim);font-size:12.5px;line-height:1.6;margin:2px 0 0}
.statusline{margin:14px 0 0;font-size:12px;color:var(--dim)}
.site .gate-toggles{display:flex;gap:14px;justify-content:flex-start;margin:2px 0 0;
  color:var(--mid);font-size:12.5px;flex-wrap:wrap}

.strip{border-block:1px solid rgba(28,35,80,.6);background:rgba(10,14,36,.5)}
.strip-in{max-width:1080px;margin:0 auto;padding:22px clamp(18px,4vw,52px);
  display:grid;grid-template-columns:repeat(4,1fr);gap:22px}
.strip-in div{display:grid;gap:3px}
.strip-in b{font-family:var(--display);font-size:15px;font-weight:600}
.strip-in span{color:var(--dim);font-size:12.5px;line-height:1.5}
@media (max-width:820px){ .strip-in{grid-template-columns:1fr 1fr} }

.modes{max-width:1140px;margin:0 auto;padding:clamp(56px,8vw,110px) clamp(18px,4vw,52px) 0;text-align:center}
.modes .lead{margin:0 auto 40px}
.cards{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;text-align:left}
.card-m{background:linear-gradient(180deg,rgba(15,20,48,.9),rgba(10,14,36,.75));
  border:1px solid var(--line);border-radius:var(--r);padding:22px;position:relative;overflow:hidden}
.card-m::after{content:'';position:absolute;inset:auto -30% -60% -30%;height:120px;
  background:radial-gradient(ellipse at center,rgba(7,148,252,.20),transparent 70%);pointer-events:none}
.card-m .tag{font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--blue);font-weight:600}
.card-m h3{font-family:var(--display);font-size:21px;font-weight:600;margin:9px 0 9px;letter-spacing:-.02em}
.card-m p{color:var(--mid);font-size:13.5px;line-height:1.65;margin:0}
@media (max-width:1000px){ .cards{grid-template-columns:1fr 1fr} }
@media (max-width:620px){ .cards{grid-template-columns:1fr} }

.split{max-width:1140px;margin:0 auto;padding:clamp(56px,8vw,110px) clamp(18px,4vw,52px) 0;
  display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(30px,5vw,64px);align-items:center}
.split.rev .split-copy{order:2}
.ticks{list-style:none;margin:20px 0 0;padding:0;display:grid;gap:9px}
.ticks li{color:var(--mid);font-size:14px;padding-left:26px;position:relative;line-height:1.6}
.ticks li::before{content:'';position:absolute;left:0;top:7px;width:13px;height:13px;border-radius:4px;
  background:var(--grad)}
@media (max-width:900px){ .split{grid-template-columns:1fr} .split.rev .split-copy{order:0} }

.split-art{display:grid;place-items:center}
.markart{width:min(320px,74%);filter:drop-shadow(0 30px 70px rgba(91,46,242,.45))}
.frame{width:100%;max-width:460px;background:var(--deepbg);border:1px solid var(--line);
  border-radius:var(--r);overflow:hidden;position:relative;box-shadow:0 30px 90px rgba(3,10,50,.6)}
.frame-bar{display:flex;gap:6px;padding:11px 14px;border-bottom:1px solid var(--line);background:rgba(15,20,48,.7)}
.frame-bar i{width:9px;height:9px;border-radius:50%;background:#1C2350}
.frame-body{display:grid;grid-template-columns:1fr 1fr;gap:8px;padding:14px}
.ft{aspect-ratio:16/10;border-radius:10px;background:linear-gradient(150deg,rgba(7,148,252,.16),rgba(91,46,242,.14));
  border:1px solid rgba(28,35,80,.9)}
.ft:nth-child(2){background:linear-gradient(150deg,rgba(91,46,242,.2),rgba(7,148,252,.1))}
.ft:nth-child(3){background:linear-gradient(200deg,rgba(7,148,252,.1),rgba(29,47,198,.18))}
.frame-rec{position:absolute;left:14px;top:52px;display:flex;align-items:center;gap:7px;
  background:rgba(5,8,23,.85);border:1px solid #5b2b31;border-radius:8px;padding:5px 10px;
  font-size:11px;font-family:var(--mono);color:var(--mid)}
.frame-rec .dot{width:8px;height:8px;border-radius:50%;background:#FF6B7A;animation:blink 1.6s infinite}

.closer{text-align:center;padding:clamp(70px,10vw,140px) clamp(18px,4vw,52px) 0;max-width:760px;margin:0 auto}
.closer .lead{margin:16px auto 26px}
.closer .cta{padding:16px 40px;font-size:17px}

.foot{max-width:1140px;margin:0 auto;padding:clamp(50px,7vw,90px) clamp(18px,4vw,52px) 46px;
  display:flex;align-items:center;justify-content:space-between;gap:16px;
  border-top:1px solid rgba(28,35,80,.6);margin-top:clamp(50px,7vw,90px)}
.footwm{height:12px;opacity:.7}
.foot span{color:var(--dim);font-size:12.5px;font-family:var(--mono)}

.statusline{display:flex;align-items:center;justify-content:center;gap:7px}
.statusline .pip{width:6px;height:6px;border-radius:50%;background:var(--good);box-shadow:0 0 8px var(--good)}

.sheet-card.narrow{width:min(520px,94vw)}
.sheet-body h3{color:var(--acc)}
.sheet-body label.row{display:flex;align-items:center;gap:9px;color:var(--mid);font-size:14px;margin:9px 0}
.sheet-body select.f{margin-top:4px}
.sheet-body .note{font-size:12.5px;color:var(--dim);margin-top:8px}


/* ═══════════════════════ small screens ═══════════════════════
   The room is the hard part on a phone: a video grid, a side panel and a control bar
   cannot all be on screen at once. So the panel becomes a sheet over the stage, the
   bar stays put above the home indicator, and the grid keeps the whole viewport. */

@media (max-width:860px){
  .hero{min-height:auto;padding-top:26px;padding-bottom:34px}
  .display{font-size:clamp(30px,8.4vw,44px)}
  .display br{display:none}
  .hero .sub{font-size:15px;margin-top:14px}
  .startcard{margin-top:22px;max-width:100%}
  .site .gate-toggles{gap:12px;font-size:12px}
  .strip-in{grid-template-columns:1fr 1fr;gap:16px;padding:20px}
  .modes,.split,.closer{padding-top:56px}
  .cards{gap:12px}
  .split-art{order:-1}
  .markart{width:52%}
  .frame{max-width:100%}
  .foot{flex-direction:column;gap:12px;text-align:center}
}

@media (max-width:900px){
  #app{grid-template-columns:1fr;grid-template-rows:1fr auto;
    grid-template-areas:"stage" "bar"}
  /* the panel slides over the meeting instead of squeezing it */
  #rail{position:fixed;inset:0 0 var(--barh) 0;z-index:30;border-left:0;
    border-top:1px solid var(--line);transform:translateY(100%);
    transition:transform .28s cubic-bezier(.2,.8,.2,1)}
  #app:not(.norail) #rail{transform:translateY(0)}
  #app.norail #rail{transform:translateY(100%)}
  #railOpen{display:inline-flex}
  #stage{padding:8px}
  #grid{gap:6px}
  /* The stage's bottom edge is BEHIND the control bar on a phone (the bar is pinned
     over it and the stage pays for it in padding), so "6px up" was under the bar.
     --barpad is that reservation; every caption offset on a phone starts from it. */
  #stage{--barpad:calc(var(--barh,106px) + 6px)}
  .captions{bottom:calc(var(--barpad) + 8px);width:calc(100% - 16px)}
  .cap-pill{font-size:13px}
  .tile .chip{left:6px;bottom:6px;font-size:11px;padding:3px 7px}
  .tile .chip .badge{font-size:9px;padding:3px 5px}
  /* ── one row ────────────────────────────────────────────────────────────
     [stated] "the notes and chat should go up so now that bottom bar can just be one
     row". It wrapped because .bar-mid was forced to 100% and pushed to order:3, which
     cost a whole row of a phone screen to hold buttons that fit beside the others.
     Notes & chat moves onto the video where there is space going spare, the engine
     name is gone, and what remains is one row that does not wrap. */
  #bar{flex-wrap:nowrap;gap:6px;padding:7px 8px calc(9px + env(safe-area-inset-bottom));
    align-items:center}
  .bar-left{min-width:0;flex:0 1 auto;overflow:hidden}
  .bar-right{flex:none;margin-left:auto}
  .bar-mid{order:0;width:auto;flex:1 1 auto;justify-content:center;gap:3px;min-width:0;
    overflow-x:auto;scrollbar-width:none}
  .bar-mid::-webkit-scrollbar{display:none}
  .ctl{width:38px;height:38px;font-size:14px;flex:none}
  .ctl.leave{padding:0 11px;font-size:12px}
  .ctl.wide-ctl{padding:0;width:38px}
  /* Leave must never be the button that falls off the end. Seven round controls at
     38px plus a share icon plus Leave is 374px of content in a 390px phone, and the
     row was overflowing by exactly the width of the word. Below 400px everything
     tightens rather than the last button being cut in half. */
  .bar-right{flex:none;margin-left:auto;min-width:0}
  .ctl.leave{flex:none}
}
/* A narrower step of its own. Nesting this inside the 900px block would have been
   invalid CSS; opening it without closing that block first left every rule in the rest
   of the file trapped inside a media query, which is how the light theme lost its
   text colours for one commit. */
@media (max-width:400px){
  #bar{gap:4px;padding-left:6px;padding-right:6px}
  .bar-mid{gap:1px}
  .ctl{width:34px;height:34px}
  .ctl.wide-ctl{width:34px}
  .ctl.leave{padding:0 9px;font-size:11.5px}
  .recdotic{width:23px;height:23px}
}
@media (max-width:900px){

  .room{padding:7px 9px;gap:0;border-radius:9px}

  /* Notes & chat, lifted onto the video. It is the one control that opens a whole
     surface, so it earns a corner rather than a slot in a row of round buttons.
     FIXED, not absolute: it lives inside #bar, and a bar 59px tall makes `top:58px`
     mean "just past the bottom of the screen". Top-left, because the top-right corner
     already belongs to the theme and layout buttons. */
  /* [stated] "lets move the close button to the left side on mobile since thats where
     the open button is". Opening happens top-left and closing happened top-right, so a
     round trip crossed the whole screen with a thumb. `display:contents` on the tools
     wrapper lets its two children take their own places in the header rather than
     travelling together — Close leads, the tabs follow, and ? stays at the end where a
     rarely-pressed thing belongs. */
  .rail-tools{display:contents}
  #railClose{order:-1;margin-right:6px}
  .tabs-top{order:0}
  #guideBtn{order:1}
  .closebtn .chev-l{display:inline}
  .closebtn .chev-r{display:none}

  #railOpen{position:fixed;left:12px;top:12px;z-index:9;
    background:rgba(8,11,16,.72);border:1px solid rgba(255,255,255,.16);color:#fff;
    backdrop-filter:blur(8px);padding:8px 13px;font-size:12.5px;border-radius:10px}
  #app.norail #railOpen{display:inline-flex}

  /* [stated] "the clip text on mobile is too small to read" — the label is hidden at
     this width, so the word on the arc is the only thing saying which button this is,
     and at 11px it said nothing. */
  .recdotic{width:26px;height:26px}
  .recdotic .clipword{font-size:6.2px}

  .ctl.wide-ctl span{display:none}
  /* Once the room code came out of this button, all that was left was a 13px glyph in
     3px of padding — the smallest target in the whole bar, and it is the one that
     copies the invite link, which is the thing a person on a phone most often wants.
     Sized to match the other controls in the row. */
  .room{font-size:11px;padding:0;width:38px;height:38px;display:grid;place-items:center;
    border-radius:11px}
  .room .shareicon{width:19px;height:19px;opacity:.9}
  button.room:active .shareicon{opacity:1;color:var(--acc2)}
  .panelbtn{padding:6px 10px;font-size:11.5px}
  #peopleTag{display:none}
  .recdots{left:10px;top:10px}
  .recdot{font-size:11px;padding:5px 9px}
  .spotbar{left:8px;top:8px;font-size:11.5px;padding:5px 9px}
  #app.strip #grid{height:92px}
  .sheet-card{padding:22px 20px;max-height:90vh}
  .sheet-body h2{font-size:19px}
  .modemenu{left:8px;right:8px}
}
:root{--barh:60px}
@media (max-width:900px){ :root{--barh:106px} }

/* ───────── the viewport, for good ─────────
   Three units have been tried here and all three lie somewhere. 100vh is the large
   viewport and hides the bar under Safari's toolbar. 100svh is the small one and
   leaves a band of background when the toolbar retracts. 100dvh is right until the
   keyboard opens, when Android reports a viewport that includes the keyboard and iOS
   does not resize at all.

   So the page does not ask CSS how tall the window is — it measures, from
   visualViewport, which is the only API that knows about the toolbar AND the
   keyboard. --vph is that measurement. The unit chain below is the fallback for the
   first paint and for anything without visualViewport, in worst-to-best order so the
   best supported one wins. */
#app{height:100vh}
@supports (height:100svh){ #app{height:100svh} }
@supports (height:100dvh){ #app{height:100dvh} }

/* Two measurements, not one. --vph is how tall the visible area is; --vtop is how far
   down the page that visible area STARTS.

   The second one is why this kept coming back. A `position:fixed` element on iOS is
   placed against the LAYOUT viewport, which includes the strip of page hidden behind
   Safari's toolbar — but --vph measures the VISUAL viewport, which does not. Pin a
   fixed element at top:0 and give it the visual height and it starts too high by
   exactly the toolbar's offset, so it ends that far below the bottom of the screen,
   and whatever is at its bottom edge — the control bar — is cut in half. Which is
   precisely what it did. Both numbers come from visualViewport; neither is guessed. */
#app{top:var(--vtop, 0px); bottom:auto; height:var(--vph, 100dvh)}

/* The control bar sits above the home indicator on every phone, and above the
   keyboard when one is open — --kb is measured too. */
#bar{padding-bottom:calc(9px + env(safe-area-inset-bottom, 0px) + var(--kb, 0px))}

/* ───────── the bar is not a grid row on a phone ─────────
   It used to be, and a grid row can be squeezed: the bar's track resolved to 0px
   while its buttons needed 106, so they hung off the bottom of the window with no
   scroll to reach them. A row that CAN collapse eventually will.

   So on a phone the bar is taken out of the grid and pinned to the bottom of the
   shell, where its height is whatever its content needs and nothing can compress it.
   The stage reserves room for it with padding, from --barh, which is MEASURED from
   the bar rather than guessed — add a button, wrap to a third line, translate the
   labels into German, and the reservation still matches. */
@media (max-width:900px){
  /* grid-auto-rows:0 matters as much as the rows above it. With the areas reduced to
     "stage", `grid-area:bar` and `grid-area:rail` no longer name anything, so the grid
     invents IMPLICIT rows for them — computed rows came out `784px 0px 60px`, and that
     stray 60px is the band of dead space between the video and the controls. The bar is
     absolutely positioned and the stage already reserves its height in padding, so the
     reservation was being made twice. */
  /* `.norail` is matched too, and that is the whole bug. `#app.norail` is an id plus a
     class, so it outranks a plain `#app` no matter which rule comes later — and on a
     phone the rail starts closed, so `.norail` is the state the room opens in. Its
     desktop rule is `1fr 0 60px`, which is exactly the `784px 0px 60px` the browser
     was computing: a 60px row still reserved for a bar that is absolutely positioned
     and already accounted for in the stage's padding. The video stopped 66px short of
     the controls because the room was paying for that bar twice.

     grid-auto-rows:0 covers the other half: with the areas reduced to "stage",
     `grid-area:bar` and `grid-area:rail` name nothing and the grid would otherwise
     invent implicit rows for them. */
  #app, #app.norail{grid-template-columns:1fr; grid-template-rows:1fr;
    grid-template-areas:"stage"; grid-auto-rows:0; grid-auto-columns:0}
  #stage{grid-row:1; grid-column:1; height:100%}
  #bar{position:absolute; left:0; right:0; bottom:0; z-index:20; height:auto}
  #stage{padding-bottom:calc(var(--barh, 106px) + 6px)}
  #rail{inset:0 0 var(--barh, 106px) 0}
}

/* ───────── dropping files in ───────── */
.dropveil{position:fixed;inset:0;z-index:60;display:none;place-items:center;pointer-events:none;
  background:rgba(5,8,23,.72);backdrop-filter:blur(6px)}
#app.dropping .dropveil{display:grid}
.dropveil>div{border:2px dashed var(--blue);border-radius:20px;padding:38px 52px;text-align:center;
  background:rgba(15,20,48,.8)}
.dropveil b{display:block;font-family:var(--display);font-size:22px;font-weight:600}
.dropveil span{display:block;color:var(--mid);font-size:13.5px;margin-top:7px}

.filecard{background:var(--panel2);border:1px solid var(--line);border-radius:12px;padding:11px 12px}
.filecard b{display:block;font-size:13px;font-style:normal;margin-bottom:8px}
.filecard img{width:100%;border-radius:9px;display:block;cursor:zoom-in;max-height:220px;object-fit:cover}
.filecard .row{display:flex;gap:9px;align-items:center;margin-top:9px}
.filecard .row a{font-size:12px;padding:6px 12px;border-radius:8px;text-decoration:none;
  background:var(--grad);color:#fff;font-weight:600}
.filecard .fname{color:var(--dim);font-size:11.5px;font-family:var(--mono);overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap;min-width:0}

/* ───────── the face bubble over a presentation ───────── */
.spotface{position:absolute;left:20px;bottom:20px;z-index:3;display:grid;justify-items:center;gap:8px;
  pointer-events:none}
.spotface[hidden]{display:none}
.spotface video.tappable{pointer-events:auto;cursor:pointer}
.spotface video{width:clamp(96px,11vw,164px);aspect-ratio:1;border-radius:50%;object-fit:cover;
  background:var(--panel2);border:3px solid transparent;
  background-image:linear-gradient(var(--panel2),var(--panel2)),var(--grad);
  background-origin:border-box;background-clip:content-box,border-box;
  box-shadow:0 14px 40px rgba(3,10,50,.65)}
.spotface span{background:rgba(5,8,23,.82);border-radius:8px;padding:3px 10px;font-size:12px;
  backdrop-filter:blur(6px);max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@media (max-width:900px){ .spotface{left:10px;bottom:10px;gap:5px} .spotface span{font-size:11px} }

/* ───────── the QuickAlign roadmap ───────── */
.step{padding:9px 0 9px 0;border-bottom:1px solid rgba(28,35,80,.55)}
.step:last-of-type{border-bottom:0}
.step .sh{display:flex;align-items:center;gap:8px}
.step .n{width:19px;height:19px;border-radius:50%;display:grid;place-items:center;flex:none;
  font-size:10.5px;font-weight:700;background:var(--field);border:1px solid var(--line);color:var(--dim)}
.step b{font-size:13.5px}
.step p{margin:5px 0 0 27px;color:var(--dim);font-size:12.5px;line-height:1.55}
.step .here{font-size:9.5px;text-transform:uppercase;letter-spacing:.08em;color:#fff;
  background:var(--grad);border-radius:5px;padding:2px 6px;font-weight:700}
.step.now .n{background:var(--grad);border-color:transparent;color:#fff}
.step.now p{color:var(--mid)}
.step.done .n{color:var(--good);border-color:#1c5c48}
.step.done b{color:var(--mid)}

/* ───────── share / meeting code ───────── */
.bigcode{font-family:var(--mono);font-size:clamp(22px,4vw,30px);letter-spacing:.1em;text-align:center;
  color:var(--blue);background:rgba(7,148,252,.08);border:1px solid rgba(7,148,252,.35);
  border-radius:14px;padding:16px;margin:14px 0}
.linkrow2{display:flex;gap:8px}
.linkrow2 input{flex:1;min-width:0;background:var(--deepbg);border:1px solid var(--line);border-radius:10px;
  padding:11px 13px;font-size:12.5px;font-family:var(--mono);color:var(--mid)}
.knock{display:flex;align-items:center;gap:10px;padding:9px 0;border-bottom:1px solid rgba(28,35,80,.55)}
.knock:last-child{border-bottom:0}
.knock .who2{flex:1;min-width:0;font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.knock button{font-size:12px;padding:7px 12px;border-radius:9px;border:1px solid var(--line);background:var(--field);color:var(--mid)}
.knock button.yes{background:var(--grad);color:#fff;border:0;font-weight:600}
.sheet-body .row span b{font-weight:600;color:var(--ink)}
.knockdot{position:absolute;top:5px;right:5px;width:9px;height:9px;border-radius:50%;background:var(--warn);
  box-shadow:0 0 8px var(--warn)}

/* ───────── phone: speaker focus ───────── */
@media (max-width:900px){
  /* the strip floats over the speaker instead of stealing height from a small screen */
  #app.focusmode #grid{position:relative}
  #app.focusmode #strip.dead{position:absolute;right:8px;bottom:8px;left:auto;height:auto;
    justify-content:flex-end;gap:6px;z-index:3}
  #app.focusmode #strip .tile{width:24vw;max-width:118px;height:auto;aspect-ratio:3/4;
    box-shadow:0 10px 26px rgba(0,0,0,.55)}
  #app.focusmode #strip .tile.me{border-color:rgba(7,148,252,.55)}
  #app.focusmode #strip .chip{font-size:10px;padding:2px 6px}
  #app.focusmode .captions{bottom:calc(var(--barpad) + 8px + 24vw * 4 / 3 + 10px)}
  .viewbtn{right:10px;top:10px;width:34px;height:34px}
}

/* ───────── reactions ───────── */
.reactwrap{position:relative}
.reactbar{position:absolute;bottom:calc(100% + 10px);left:50%;transform:translateX(-50%);
  display:flex;gap:4px;padding:8px;background:var(--panel2);border:1px solid var(--line);
  border-radius:16px;box-shadow:0 20px 50px rgba(3,10,50,.7);z-index:20}
.reactbar[hidden]{display:none}
.reactbar button{width:44px;height:44px;border-radius:50%;font-size:24px;line-height:1;
  display:grid;place-items:center;transition:transform .12s}
.reactbar button:hover{transform:scale(1.25) translateY(-2px);background:var(--panel3)}
.reactbar button:active{transform:scale(.95)}

#floats{position:absolute;inset:0;pointer-events:none;overflow:hidden;z-index:6}
.float{position:absolute;display:flex;flex-direction:column;align-items:center;gap:3px;
  animation:floatup var(--dur,3.6s) cubic-bezier(.22,.7,.3,1) forwards}
.float .em{font-size:var(--size,42px);line-height:1;filter:drop-shadow(0 6px 14px rgba(0,0,0,.5))}
.float .nm2{font-size:10.5px;color:var(--ink);background:rgba(5,8,23,.72);border-radius:6px;
  padding:1px 6px;backdrop-filter:blur(4px)}
@keyframes floatup{
  0%{opacity:0;transform:translateY(0) scale(.5) rotate(var(--r0,0deg))}
  12%{opacity:1;transform:translateY(-14px) scale(1.15) rotate(var(--r0,0deg))}
  100%{opacity:0;transform:translateY(-62vh) translateX(var(--dx,0px)) scale(.9) rotate(var(--r1,0deg))}
}
.tile.handup{border-color:var(--warn);box-shadow:inset 0 0 0 2px rgba(245,184,81,.6)}
.tile .hand{position:absolute;right:10px;top:10px;font-size:20px;
  animation:wave 1.6s ease-in-out infinite;transform-origin:70% 80%}
@keyframes wave{0%,100%{transform:rotate(-8deg)}50%{transform:rotate(12deg)}}

/* the file card was wrapping "Open" onto two lines */
.filecard .row a{white-space:nowrap;flex:none}
.filecard .row .dl{background:var(--field);border:1px solid var(--line);color:var(--mid);font-weight:500}

.chatbox-wrap{position:relative;flex:1;min-width:0}
.chatbox-wrap input{width:100%}
.atmenu{position:absolute;bottom:calc(100% + 6px);left:0;right:0;background:var(--panel2);
  border:1px solid var(--line);border-radius:12px;padding:5px;z-index:20;
  box-shadow:0 18px 44px rgba(3,10,50,.7)}
.atmenu[hidden]{display:none}
.atmenu button{display:block;width:100%;text-align:left;padding:8px 10px;border-radius:8px;font-size:13px;color:var(--mid)}
.atmenu button:hover{background:var(--panel3);color:var(--ink)}
.atmenu button.ai{color:var(--blue);font-weight:600}

/* Audio sinks: present, playing, and never laid out or moved. */
#sinks{position:fixed;width:0;height:0;overflow:hidden;pointer-events:none;opacity:0}
/* Ova's Stop — top-centre of the stage, and only there while she is thinking or
   answering. 60px down, not 12: the toasts own the top 50px of the window and a phone's
   corner buttons the top 52px of the stage, and either one covering Stop for three
   seconds is three seconds she keeps talking. Its own dark surface and light text, so
   it reads the same in either theme over any picture. Solid, not a gradient. */
.ovapill{position:absolute;left:50%;transform:translateX(-50%);top:60px;z-index:12;
  display:flex;align-items:center;gap:10px;padding:5px 5px 5px 13px;border-radius:999px;
  background:rgba(13,17,30,.94);border:1px solid rgba(142,162,255,.38);color:#e9edff;
  font-size:13px;font-weight:500;white-space:nowrap;box-shadow:0 8px 28px rgba(0,0,0,.45)}
.ovapill[hidden]{display:none}
.ovapill button{background:#e5484d;color:#fff;border-radius:999px;padding:6px 15px;font-size:12.5px;font-weight:650;line-height:1}
.ovapill button:hover{background:#f05a5f}
.ovaorb{display:inline-flex;gap:2px;align-items:flex-end;height:12px}
.ovaorb i{display:block;width:3px;height:4px;border-radius:2px;background:#8ea2ff;animation:ovabar 1s ease-in-out infinite}
.ovaorb i:nth-child(2){animation-delay:.15s}
.ovaorb i:nth-child(3){animation-delay:.3s}
.ovapill.thinking .ovaorb i{animation-duration:1.8s;opacity:.65}
@keyframes ovabar{0%,100%{height:4px}50%{height:12px}}
@media (prefers-reduced-motion:reduce){.ovaorb i{animation:none;height:8px}}
.audiowarn{position:absolute;left:50%;transform:translateX(-50%);top:12px;z-index:8;
  background:rgba(44,26,30,.92);border:1px solid #5b2b31;color:#f8cfcf;border-radius:10px;
  padding:8px 14px;font-size:13px;display:flex;align-items:center;gap:10px}
.audiowarn[hidden]{display:none}
.audiowarn button{background:var(--grad);color:#fff;border-radius:8px;padding:5px 11px;font-size:12px;font-weight:600}


/* ───────── pin, mute-for-me, and the agent row ───────── */
/* Top-right, not bottom-right. The picture-in-picture lives in the bottom-right corner
   of the room and sits above every tile, so pin and mute were unreachable on whichever
   tile happened to be underneath it — visible, and impossible to click. Two things that
   both want the same corner is a bug waiting for the day somebody has one guest. */
.tileacts{position:absolute;right:6px;top:6px;display:flex;gap:5px;opacity:0;transition:opacity .14s;z-index:3}
.tile:hover .tileacts,.tile:focus-within .tileacts{opacity:1}
@media (hover:none){ .tileacts{opacity:.75} }
.tileact{width:30px;height:30px;border-radius:9px;border:1px solid var(--line);
  background:rgba(5,8,23,.72);backdrop-filter:blur(6px);color:var(--ink);font-size:13px;
  cursor:pointer;display:grid;place-items:center;padding:0;line-height:1}
.tileact:hover{border-color:var(--blue)}
.tile.pinned .tileact.pin{background:var(--blue);border-color:var(--blue);color:#fff}
.tile.mutedforme .tileact.mute{background:#b3402f;border-color:#b3402f;color:#fff}
.tile.pinned{outline:2px solid var(--blue);outline-offset:-2px}
.tile.mutedforme video{filter:grayscale(.5) brightness(.82)}
.tile.mutedforme .chip .nm::after{content:' · muted for you';opacity:.75;font-weight:400}

/* Your own picture reads as a mirror; what is sent never is. */
video.mirror{transform:scaleX(-1)}

.person{display:flex;align-items:center;gap:9px;padding:8px 0;border-bottom:1px solid var(--line)}
.person:last-child{border-bottom:0}
.person .who2{flex:1;min-width:0;font-size:13.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.person button{font-size:11.5px;padding:5px 10px;border-radius:8px;border:1px solid var(--line);
  background:var(--panel2);color:var(--ink);cursor:pointer;white-space:nowrap}
.person button:hover{border-color:var(--blue)}
.person button.yes{background:var(--blue);border-color:var(--blue);color:#fff}
.tagagent{font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;padding:3px 7px;border-radius:6px;
  background:linear-gradient(120deg,var(--blue),var(--violet));color:#fff;font-weight:600}
.tile .badge.agentbadge{background:linear-gradient(120deg,var(--blue),var(--violet))}

.footnav{display:flex;gap:18px;flex-wrap:wrap;flex:1;justify-content:center}
.footnav a{color:var(--dim);font-size:13px;text-decoration:none}
.footnav a:hover{color:var(--ink)}
@media (max-width:700px){ .footnav{justify-content:flex-start;gap:14px;order:3;width:100%} }


/* ═══════════════════════ the key light ═══════════════════════
   A light theme lifts the interface. It does not light your face, because in a call
   most of the screen is other people's video and that is whatever colour their room
   is. What lights your face is a large, bright, close surface — which a laptop panel
   is, if you let it be one.

   So: a frame of warm white around the meeting, brightness on a slider, sitting above
   the video and below every control. It is yours alone. Nobody else sees it, nothing
   is sent, and it does not appear in a recording — it is a lamp, not a filter. */
#keylight{
  position:fixed; inset:0; z-index:8; pointer-events:none;
  opacity:0; transition:opacity .25s ease;
  --kl:0;                       /* 0…1, the slider */
  --klw:clamp(46px, 7vw, 120px);
}
#keylight.on{ opacity:1 }
#keylight::before{
  content:''; position:absolute; inset:0;
  /* brightest at the top, because that is the angle that flatters a face and the
     part of the panel closest to the camera */
  background:
    linear-gradient(180deg, rgba(255,247,236,calc(.96 * var(--kl))) 0%,
                            rgba(255,247,236,calc(.55 * var(--kl))) 42%,
                            rgba(255,247,236,0) 100%) top / 100% var(--klw) no-repeat,
    linear-gradient(0deg,   rgba(255,247,236,calc(.42 * var(--kl))) 0%,
                            rgba(255,247,236,0) 100%) bottom / 100% calc(var(--klw) * .7) no-repeat,
    linear-gradient(90deg,  rgba(255,247,236,calc(.62 * var(--kl))) 0%,
                            rgba(255,247,236,0) 100%) left / calc(var(--klw) * .8) 100% no-repeat,
    linear-gradient(270deg, rgba(255,247,236,calc(.62 * var(--kl))) 0%,
                            rgba(255,247,236,0) 100%) right / calc(var(--klw) * .8) 100% no-repeat;
}
#keylight.cool::before{ filter:hue-rotate(-14deg) saturate(.35) }

.klrow{display:flex;align-items:center;gap:12px;margin:10px 0 0}
.klrow input[type=range]{flex:1;accent-color:var(--acc)}
.klrow .klval{font-family:var(--mono);font-size:11.5px;color:var(--dim);
  min-width:3.2em;text-align:right;font-variant-numeric:tabular-nums}
.kltemp{display:flex;gap:8px;margin:10px 0 0}
.klrow.kloff,.kltemp.kloff{opacity:.45;transition:opacity .15s}
.klrow.kloff:hover,.kltemp.kloff:hover{opacity:.8}
.kltemp button{flex:1;font-size:12px;padding:7px 10px;border-radius:9px;
  border:1px solid var(--line);background:var(--panel2);color:var(--mid);cursor:pointer}
.kltemp button.on{border-color:var(--acc);color:var(--ink);background:var(--onbg)}

/* Theme picker — three states, because "match my system" is the honest default. */
.themepick{display:flex;gap:8px;margin:8px 0 0}
.themepick button{flex:1;display:flex;flex-direction:column;align-items:center;gap:6px;
  padding:11px 8px;border-radius:11px;border:1px solid var(--line);
  background:var(--panel2);color:var(--mid);cursor:pointer;font-size:12px}
.themepick button:hover{border-color:var(--edge2);color:var(--ink)}
.themepick button.on{border-color:var(--acc);color:var(--ink);background:var(--onbg)}
.themepick .sw{width:100%;height:26px;border-radius:7px;border:1px solid var(--line)}
.themepick .sw-dark{background:linear-gradient(160deg,#0A0E24 55%,#1C2350)}
.themepick .sw-light{background:linear-gradient(160deg,#FFFFFF 55%,#DCE2F2)}
.themepick .sw-auto{background:linear-gradient(105deg,#0A0E24 0 50%,#FFFFFF 50% 100%)}


/* The transcript is the thing people come back for, and today it is thrown away a few
   hours after the meeting. That is worth saying where they are reading it. */
.txkeep{margin:0;padding:14px 15px;border-top:1px solid var(--line);background:var(--panel2);
  display:flex;flex-direction:column;gap:7px}
.txkeep[hidden]{display:none}
.txkeep b{font-size:13px;color:var(--ink);font-weight:600;line-height:1.35}
.txkeep span{font-size:12.5px;color:var(--mid);line-height:1.5}
.txkeep .btn.go{align-self:flex-start;background:var(--grad);color:#fff;border:0;
  padding:8px 14px;border-radius:9px;font-size:12.5px;font-weight:600;cursor:pointer}


/* ───────── anything painted over video ─────────
   These keep their own contrast in both themes. A person's camera shows a bright
   window or a dark wall and neither follows your theme setting, so a name chip that
   flipped to dark-on-white would be unreadable half the time. */
.tile .chip, .tile .chip .nm{ color:#F4F7FF }
.tile .chip .role{ color:#AEB9D6 }
.tile .avatar{ background:rgba(10,14,36,.82); color:#C7D0E8 }
/* The initial in the person's own colour — the one on their name chip and their lines
   in the transcript — so a tile without a picture still says at a glance who it is. */
.tile .avatar{ background:color-mix(in srgb, var(--who, #5b6b9a) 30%, #0b1024);
  color:#F4F7FF; box-shadow:0 0 0 1.5px color-mix(in srgb, var(--who, #5b6b9a) 55%, transparent) }
.tileact{ background:rgba(5,8,23,.78); border-color:rgba(255,255,255,.16); color:#F4F7FF }
.tileact:hover{ border-color:var(--acc); background:rgba(5,8,23,.92) }
/* Everything drawn over the video keeps light text in both themes. */
#grid, #grid *, .spotbar, .spotbar *, .recdots, .recdots *, .captions, .captions *,
#viewBtn, .float, .hand{ color:#F4F7FF }
#grid .chip .role{ color:#AEB9D6 }
#viewBtn{ background:rgba(8,11,16,.75); border-color:rgba(255,255,255,.16) }


/* ───────── one container, no tile ever moves ─────────
   The stage and the filmstrip are grid AREAS now, not separate parents. A tile keeps
   its place in the DOM for the whole call and only its grid-area changes, so nothing
   restarts when the speaker does: not the video, not the screen share, not the audio.
   Everything below is placement and size — the tile itself is untouched. */
#stagearea.focused{
  align-content:stretch;
  justify-content:stretch;
  grid-auto-flow:row;
}
/* ── THE RULE, after the phone-on-a-shared-screen bug ──────────────────────
   [stated] "When screen is shared the video was getting a weird crop … really
   figure this out so it never happens again, or a decision like this is never
   made within the software to do something so silly."

   What happened: the presenting rule below was written as `#stagearea .tile` —
   a blanket over EVERY tile — and two ids beat the picture-in-picture's own
   `.tile.selfpip` rule. So while somebody presented, your own tile was handed
   the strip's `height:100%` and `aspect-ratio:16/9`, and a phone's portrait
   picture was then cover-cropped into a landscape box: the ceiling, with the
   person below the edge. Three decisions, each fine alone, silly together.

   The rule that stops the class of bug, not just this instance:
     1. The self picture-in-picture is NOT a stage tile and NOT a strip tile.
        Every stage/strip rule is scoped `:not(.selfpip)`, and the pip's box is
        decided in ONE place (below, `#stagearea .tile.selfpip`).
     2. A tile's shape follows its PICTURE. A portrait picture — a phone held
        upright — gets a portrait box, not a landscape box with the middle cut out.
        Big tiles show the whole picture (`contain`); thumbnails (the strip, the
        pip) are boxed to the picture's own shape and filled.
     3. A tile's video box IS the tile's box (`position:absolute; inset:0`, above),
        whatever the picture's intrinsic size — so nothing can overflow and clip.
   test/video-shape.mjs drives every layout on a laptop and a phone with a real
   portrait capture and asserts all three, so a rule that breaks them fails a test
   before it reaches a call. */
#stagearea.focused .tile:not(.selfpip){ width:auto; height:auto; min-width:0; min-height:0 }
#stagearea .tile{
  transition:opacity .18s ease;
  contain:layout paint;          /* a tile resizing cannot reflow its neighbours */
}
/* the filmstrip row: a consistent shape, never a stretched rectangle */
#stagearea.focused .tile.instrip{
  aspect-ratio:16/9;
  height:100%;
  width:auto;
  max-width:100%;                /* a big room's thumbnails are narrowed together, never overlapped */
  justify-self:center;
  align-self:end;
}
#stagearea.focused .tile.stage:not(.selfpip){ aspect-ratio:auto; justify-self:center; align-self:center }
/* A thumbnail of a portrait picture is a portrait thumbnail, filled to the face —
   not a landscape one with a stamp in the middle, not one with the head cut off. */
#stagearea.focused .tile.instrip:has(video.portrait){ aspect-ratio:3/4 }

/* Presenting, or a picture up: the stage holder owns the frame and every face sits in
   the strip. The picture used to have a copy of these rules without `:not(.selfpip)`
   — the exact blanket this comment warns about — and the pip became the whole stage
   behind the picture, on a laptop and on both phones. One selector now. */
/* The rows are renderGrid's: one row of the strip's height, or — in a room too big to fit
   across — two or three rows of smaller thumbnails sharing that height. */
#app.strip #stagearea{ align-content:end }
/* Placed by renderGrid, thumbnail k in column k + 2 between two spacers — not
   auto-placed, which would put the first face in the left spacer. */
#app.strip #stagearea .tile:not(.selfpip){ aspect-ratio:16/9; height:100%;
  width:auto; justify-self:center; align-self:center; max-width:100% }
#app.strip #stagearea .tile:not(.selfpip):has(video.portrait){ aspect-ratio:3/4 }
#app.strip #stagearea .tile:not(.selfpip) video{ object-fit:cover }
/* In the strip you are a thumbnail like everyone else (renderGrid drops the pip), so
   nothing floats over the corner of what is being shown. If a pip ever is here, it
   goes above the strip rather than on top of the faces. */
#app.strip #stagearea .tile.selfpip{ bottom:calc(100% + 12px) }
/* The presenter is not in the strip at all — their face is the circle over their own
   screen. See renderGrid. */

/* The old absolute-positioned phone strip fought the grid; the grid handles it. */
@media (max-width:900px){
  #stage{--striph:96px}
  #app.focusmode #strip{display:none}
  /* "in the mode pane" does not fit on a 96px thumbnail; the dot on the chip can wait */
  #app.strip .tile .whereat{display:none}
}

/* ───────── the room shows everyone, and you are in the corner ─────────
   At every width. No stage that swaps, nothing that changes position when somebody
   starts talking, and your own tile out of the layout entirely so it cannot be moved
   by your own voice. The person speaking gets a ring. See renderGrid for why. */
#stagearea.roomgrid{
  align-content:stretch; justify-content:stretch;
  grid-auto-flow:row; gap:10px;
}
/* A tile is a 16:9 box, always, and the video fills it. It is NOT stretched to whatever
   shape the grid cell happens to be.
   [stated] "the cropping to these weird rectangle sizes should never be done, need to
   respect the size of video for people." Two people across a wide strip gave each of
   them a 750×155 slot, which crops a face to a letterbox band. Fixing the shape and
   centring what is left is what every conferencing product does, and it is why their
   grids look calm while a stretched one looks broken. */
#stagearea.roomgrid .tile{
  width:auto; height:auto; min-width:0; min-height:0;
  aspect-ratio:16/9;
  justify-self:center; align-self:center;
  max-width:100%; max-height:100%;
}
/* A tile with `width:auto;height:auto` and a fixed aspect-ratio has no size of its own
   to grow from — in a big empty cell it collapses to a stamp in the middle, which is
   what Jack saw sitting alone in a room. Filling the cell and letting aspect-ratio cap
   it is the way round that actually grows. */
#stagearea.roomgrid .tile{width:100%;height:100%}
#app.roomgrid #stagearea{align-items:center;justify-items:center}
/* One person in the room — yours takes the whole frame rather than a 16:9 letterbox
   inside it, because there is nothing to line it up against. */
#app.roomgrid.alone #stagearea .tile{aspect-ratio:auto}
/* The picture-in-picture is positioned against #grid, which is deliberately NOT a
   scroll container: an absolutely positioned child of a scroller is clipped by it and
   scrolls away with the content. */
#app.haspip #grid{position:relative}
#stagearea .tile.selfpip{
  position:absolute; right:14px; bottom:14px; z-index:6;
  width:clamp(112px, 15vw, 210px);
  height:auto; aspect-ratio:16/9;
  border-radius:12px; overflow:hidden;
  border:1px solid rgba(255,255,255,.16);
  box-shadow:0 12px 34px rgba(0,0,0,.6);
  transition:none;                     /* it never moves, so it never animates */
}
/* The pip's box follows its picture: a portrait camera gets a portrait pip, on any
   device. Width stays the pip's; only the shape changes. */
#stagearea .tile.selfpip:has(video.portrait){ aspect-ratio:3/4 }
@media (max-width:900px){
  #stagearea.roomgrid{gap:6px}
  /* Portrait by default, because a phone camera usually is, and 16:9 crops your
     own chin off; a phone held sideways sends a landscape picture and gets a
     landscape pip the moment the picture says so. */
  #stagearea .tile.selfpip{right:10px;bottom:10px;width:26vw;max-width:124px;
    min-width:84px;aspect-ratio:3/4}
  #stagearea .tile.selfpip:has(video.landscape){aspect-ratio:16/9}
}
#stagearea .tile.selfpip .chip{font-size:10px;padding:2px 6px;left:5px;bottom:5px}
#stagearea .tile.selfpip .chip .role,
#stagearea .tile.selfpip .tileacts{display:none}
/* the initial in the corner picture is sized by --av, like every other tile's */
/* Captions clear the picture-in-picture rather than sitting under it. */
#app.haspip .captions{bottom:calc(14px + clamp(112px,15vw,210px) * 9 / 16 + 10px)}
@media (max-width:900px){
  /* Above the pip, which itself sits above the bar's reservation — a caption that only
     cleared the pip's own height landed on top of your own face in every phone call. */
  #app.haspip .captions{bottom:calc(var(--barpad) + 10px + 26vw * 4 / 3 + 8px)}
}


/* ───────── goals ─────────
   A checklist the meeting fills in. The quote under a ticked goal is not decoration:
   it is the difference between a checklist you trust and one you have to re-check. */
#goalsPane{flex:1;min-height:0;overflow:auto;padding:14px}
.gempty h3{font-family:var(--display);font-size:16px;font-weight:600;margin:2px 0 8px;color:var(--ink)}
.gempty p{color:var(--mid);font-size:13px;line-height:1.6;margin:0 0 12px}
#goalsIn{width:100%;box-sizing:border-box;background:var(--sunk,rgba(255,255,255,.04));
  border:1px solid var(--line);border-radius:10px;color:var(--ink);padding:10px 12px;
  font:inherit;font-size:13px;line-height:1.55;resize:vertical;outline:none}
#goalsIn:focus{border-color:var(--blue)}
.growrow{display:flex;align-items:center;gap:12px;margin-top:10px;flex-wrap:wrap}
.growrow .primary{background:var(--grad);color:#fff;border:0;border-radius:9px;
  padding:9px 16px;font-size:13px;font-weight:600;cursor:pointer}
.growrow .primary:disabled{opacity:.55;cursor:default}
.gfile span{color:var(--dim);font-size:12.5px;cursor:pointer;text-decoration:underline;
  text-underline-offset:3px}
.gfile span:hover{color:var(--ink)}
.gnote{color:var(--dim);font-size:12px;margin:9px 0 0;min-height:1em}

.ghead{display:flex;align-items:center;gap:10px;margin-bottom:12px}
.gbar{flex:1;height:5px;border-radius:3px;background:var(--sunk,rgba(255,255,255,.07));overflow:hidden}
.gbar i{display:block;height:100%;width:0;background:var(--grad);transition:width .5s cubic-bezier(.2,.8,.2,1)}
.gmeta{display:flex;flex-direction:column;line-height:1.25}
.gmeta b{font-size:12px;color:var(--ink);white-space:nowrap}
.gmeta span{font-family:var(--mono);font-size:10px;color:var(--dim)}

.goal{display:flex;gap:10px;padding:11px 0;border-bottom:1px solid var(--line)}
.goal:last-child{border-bottom:0}
.gtick{flex:none;width:20px;height:20px;margin-top:1px;border-radius:6px;cursor:pointer;
  border:1.5px solid var(--line);background:transparent;color:#fff;font-size:12px;
  line-height:1;display:grid;place-items:center;transition:.16s}
.gtick:hover{border-color:var(--blue)}
.goal.done .gtick{background:var(--good);border-color:var(--good)}
.goal.touched .gtick{border-color:var(--warn)}
.gmain{min-width:0;flex:1}
.gtitle{font-size:13.5px;line-height:1.45;color:var(--ink);font-weight:500}
.goal.done .gtitle{color:var(--mid)}
.gsub{display:flex;align-items:baseline;gap:8px;margin-top:3px;flex-wrap:wrap}
.gkind{font-family:var(--mono);font-size:9.5px;letter-spacing:.05em;text-transform:uppercase;
  padding:2px 6px;border-radius:5px;background:var(--sunk,rgba(255,255,255,.06));color:var(--dim)}
.gkind.decision{color:#8FB6FF}.gkind.action{color:#F0B37E}
.gkind.alignment{color:#C4A2FF}.gkind.information{color:#84CFC0}
.gwhen2{font-size:11.5px;color:var(--dim);line-height:1.5}
.gout{font-size:12.5px;color:var(--good);margin-top:5px;line-height:1.5}
.gowner{font-size:11.5px;color:var(--mid);margin-top:3px}
.gquote{margin-top:5px;font-size:11.5px;line-height:1.55;color:var(--dim);
  border-left:2px solid var(--line);padding-left:9px}
.gsaid{display:block;font-family:var(--mono);font-size:10px;margin-top:2px}
.ghand{font-family:var(--mono);font-size:9.5px;color:var(--warn);margin-top:5px;letter-spacing:.02em}
#goalsNew{margin-top:16px;padding-top:12px;border-top:1px dashed var(--line)}
#goalsNew h4{font-size:11px;font-family:var(--mono);letter-spacing:.05em;text-transform:uppercase;
  color:var(--dim);margin:0 0 8px;font-weight:500}
.gnew{padding:7px 0}
.gcount{position:absolute;top:3px;right:2px;padding:0 5px;height:15px;border-radius:8px;
  background:var(--sunk,rgba(255,255,255,.1));color:var(--mid);font-family:var(--mono);
  font-size:9.5px;line-height:15px;font-style:normal;box-shadow:0 0 0 2px var(--panel)}
.gcount.all{background:var(--good);color:#fff}


/* ───────── Clip past ─────────
   Two handles over a track that stands for the minutes held in this tab. Deliberately
   not a scrubbing preview: picking a moment you remember from thirty seconds ago does
   not need a frame-accurate viewer, it needs a drag that takes two seconds. */
.past-card{max-width:520px}
.past-sub{color:var(--mid);font-size:13.5px;line-height:1.6;margin:0 0 18px}
.ptrack{position:relative;height:54px;border-radius:12px;cursor:pointer;
  background:var(--sunk,rgba(255,255,255,.05));border:1px solid var(--line);
  background-image:repeating-linear-gradient(90deg,transparent 0 23px,var(--line) 23px 24px)}
.psel{position:absolute;top:-1px;bottom:-1px;border-radius:10px;
  background:linear-gradient(180deg,rgba(7,148,252,.30),rgba(81,36,216,.30));
  border:1.5px solid var(--blue);box-shadow:0 0 24px rgba(7,148,252,.28)}
.phandle{position:absolute;top:50%;transform:translateY(-50%);width:14px;height:34px;
  border-radius:7px;background:var(--blue);cursor:ew-resize;
  box-shadow:0 2px 10px rgba(0,0,0,.5)}
.phandle::after{content:'';position:absolute;inset:12px 5px;border-left:1px solid rgba(255,255,255,.65);
  border-right:1px solid rgba(255,255,255,.65)}
.phandle.l{left:-8px}
.phandle.r{right:-8px}
/* A 14px grip is a hard target on a phone, so the touch area is bigger than the paint. */
.phandle::before{content:'';position:absolute;inset:-12px -14px}
.prow{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-top:14px;flex-wrap:wrap}
.prow.end{justify-content:flex-end;margin-top:20px}
.plen{font-family:var(--mono);font-size:13px;color:var(--ink)}
.pquick{display:flex;gap:6px}
.pquick button{all:unset;cursor:pointer;font-size:11.5px;color:var(--dim);padding:5px 10px;
  border:1px solid var(--line);border-radius:999px}
.pquick button:hover{color:var(--ink);border-color:var(--blue)}
.past-card .primary{background:var(--grad);color:#fff;border:0;border-radius:10px;
  padding:10px 18px;font-size:13.5px;font-weight:600;cursor:pointer}
.past-card .primary:disabled{opacity:.55;cursor:default}
.past-card .ghost{background:none;border:1px solid var(--line);color:var(--mid);
  border-radius:10px;padding:10px 16px;font-size:13.5px;cursor:pointer}
.past-note{color:var(--dim);font-size:12px;margin:12px 0 0;min-height:1em}

/* ───────── the ask row's megaphone, and the image spotlight ───────── */
.rail-ask .loud{flex:none;padding:0 12px;font-size:15px}
.shot{position:relative}
.shot .shotacts{position:absolute;top:6px;right:6px;display:flex;gap:6px;opacity:0;transition:opacity .14s}
.shot .shotacts .btn{font-size:11px;padding:4px 9px;background:rgba(5,8,23,.82);backdrop-filter:blur(6px);color:#e9edff;border-color:rgba(255,255,255,.22)}
.shot:hover .shotacts,.shot .shotacts:focus-within{opacity:1}
@media (hover:none){ .shot .shotacts{opacity:.9} }
/* [stated] "they should be pinnable to the video (but act like a video slot rather
   than remove all view)". This was inset:0 over a blurred backdrop, so putting a
   picture in front of people made everybody disappear — the opposite of what showing
   somebody something is for. It takes the stage the way a shared screen does: faces
   drop to the strip along the bottom and stay there the whole time. */
/* Not an overlay any more. The picture is a flex child of the stage, in front of the
   grid, so the strip of faces is laid out BELOW it rather than under it, and on a
   phone the control bar — which the stage already pays for in padding — cannot cover
   its buttons. Its size is set in pixels by fitSpot(): the shape of the picture, no
   bigger than the room above the strip (see the tiles for why CSS cannot do that). */
.imgspot{position:relative;flex:1 1 auto;min-height:0;min-width:0;z-index:5;
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;padding:8px 4px 0}
/* [stated] "WHEN I CLICK SHOW FOR EVERYONE HAVE IT SHOW BIG". On a laptop the
   picture runs out of HEIGHT long before width — in the call it was 944×528 on a
   1512×827 window, with 209px of the stage spent on other things. So while it is up:
   8px above it instead of 30; on a screen big enough to have a 118px strip, a strip
   88px tall and a grid that follows it instead of staying 132px (a phone held
   sideways keeps its own 68px strip); and, where
   there is a mouse, the caption and buttons float over the picture's foot and show on
   hover, instead of taking a row of their own. */
@media (min-width:901px) and (min-height:600px){
  #app.imgstage #stage{--striph:88px}
  #app.imgstage.strip #grid{height:calc(var(--striph) + 14px)}
}
/* [stated, 2026-10-24] "WHEN I CLICK SHOW EVERYONE ITS SMALL. LETS HAVE THAT SHOW LARGE" ·
   "CLICK TO SHOW EVERYONE GO LARGE (ME ONLY) (SHOW EVERYONE) HALF AND HALF WOULD BE
   PERFECT". On a computer a picture up is HALF the stage and the people are the other
   half, as a grid of faces (renderGrid's `split`); the panel steps aside for it
   (stepRailAside), so the halves are halves of the whole window. */
#app.halfhalf #stage{flex-direction:row;align-items:stretch}
#app.halfhalf .imgspot{flex:0 0 calc(var(--hh,50%) - 5px);max-width:calc(var(--hh,50%) - 5px);padding:4px 0 0}
#app.halfhalf #grid{flex:1 1 0;min-width:0;height:auto}
#app.halfhalf.imgstage .captions{left:calc(var(--hh,50%) / 2);bottom:24px;width:min(560px,calc(var(--hh,50%) - 40px))}
/* Half the stage is taller than a wide picture needs, so its caption and buttons sit in
   a row right under it, always showing — "Show everyone" on a Me-only picture is the
   next thing to press, and it should not wait for a hover to be found. */
#app.halfhalf .imgspot .isp-bar{position:static;transform:none;opacity:1;max-width:100%;
  background:rgba(8,11,16,.86);border:1px solid rgba(255,255,255,.16);border-radius:12px;padding:6px 6px 6px 14px}
#app.halfhalf .imgspot .isp-bar .isp-cap{color:#e9edff}
#app.halfhalf .imgspot .isp-bar .ghosty{color:#e9edff;border-color:rgba(255,255,255,.28)}
/* A picture up while somebody shares their screen: the screen and the picture side by
   side, the faces in the strip under both (renderGrid's `duo`). Grid, not flex, so the
   strip can run under both halves. */
#app.duo #stage{display:grid;grid-template-columns:minmax(0,var(--duoL,1fr)) minmax(0,var(--duoR,1fr));grid-template-rows:minmax(0,1fr) auto;gap:10px}
#app.duo #stage > #spotlight{grid-column:1;grid-row:1;min-height:0;min-width:0}
#app.duo #stage > .imgspot{grid-column:2;grid-row:1;min-height:0;min-width:0;padding:0}
#app.duo #stage > #grid{grid-column:1 / -1;grid-row:2;min-width:0}
#app.duo.presenting.imgstage .spotbar{display:flex}
#app.duo.presenting.imgstage .spotface:not([hidden]){display:grid}
/* Me only: Take down is for a picture the room has up; Show everyone is for mine. */
.imgspot .ispall{display:none}
.imgspot.mine .ispall{display:inline-flex}
.imgspot.mine .ispdown{display:none}
.imgspot .ispall{background:linear-gradient(90deg,#0794FC,#5B2EF2);color:#fff;border:0}
/* Follow new pictures: on, it says so — a green border and a live dot. */
.imgspot .ispfollow{display:inline-flex;align-items:center;gap:7px}
.imgspot .ispfollow.on{border-color:var(--good);color:var(--ink)}
.imgspot .ispfollow.on::before{content:'';width:7px;height:7px;border-radius:50%;background:var(--good);
  box-shadow:0 0 0 0 color-mix(in srgb,var(--good) 60%,transparent);animation:ispLive 1.8s ease-out infinite}
@keyframes ispLive{0%{box-shadow:0 0 0 0 color-mix(in srgb,var(--good) 55%,transparent)}100%{box-shadow:0 0 0 7px transparent}}
@media (prefers-reduced-motion:reduce){.imgspot .ispfollow.on::before{animation:none}}

/* ── pictures, as they are made: a small layered stack beside the panel ─────────────
   [stated, 2026-10-24] "POP IN ON DESKTOP TO THE LEFT OF THE NOTES FEED LAYERED OVER
   ANOTHER LIKE A COLUMN SMALL". Newest on top, the ones before it layered behind; a
   hover spreads them out, and each card is two halves: Me only, Show everyone. */
.picstack{position:absolute;right:14px;top:62px;z-index:6;display:flex;flex-direction:column;align-items:flex-end;gap:6px;pointer-events:none}
.picstack[hidden]{display:none}
.picstack .ps-head,.picstack .ps-deck{pointer-events:auto}
.ps-tog{all:unset;cursor:pointer;font-size:12px;line-height:1;padding:5px 10px;border-radius:999px;
  background:rgba(8,11,16,.72);color:#e9edff;border:1px solid rgba(255,255,255,.16);backdrop-filter:blur(6px)}
.ps-tog:hover{border-color:rgba(255,255,255,.4)}
.ps-deck{position:relative;width:200px;height:calc(112px + (var(--n) - 1) * 14px);transition:height .25s ease}
.picstack:hover .ps-deck{height:calc(var(--n) * 120px - 8px)}
.ps-card{position:absolute;left:0;top:0;width:200px;height:112px;transform-origin:top center;
  transform:translateY(calc(var(--i) * 14px)) scale(calc(1 - var(--i) * .05));
  z-index:calc(10 - var(--i));filter:brightness(calc(1 - var(--i) * .14));
  transition:transform .25s ease,filter .25s ease}
.picstack:hover .ps-card{transform:translateY(calc(var(--i) * 120px));filter:none}
.ps-in{position:relative;width:100%;height:100%;border-radius:12px;overflow:hidden;background:#05070a;
  border:1px solid rgba(255,255,255,.18);box-shadow:0 12px 30px rgba(0,0,0,.5)}
.ps-card.wide .ps-in{border:3px solid transparent;
  background:linear-gradient(#05070a,#05070a) padding-box,linear-gradient(120deg,#0794FC,#5B2EF2 60%,#F5C542) border-box}
.ps-card.up .ps-in{box-shadow:0 0 0 2px #2FD39A,0 12px 30px rgba(0,0,0,.5)}
.ps-in img{display:block;width:100%;height:100%;object-fit:cover}
.ps-tag{position:absolute;left:6px;top:6px;font-size:9.5px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
  color:#fff;background:rgba(8,11,16,.72);padding:3px 6px;border-radius:6px;pointer-events:none}
.ps-acts{position:absolute;inset:0;display:grid;grid-template-columns:1fr 1fr;opacity:0;transition:opacity .15s ease}
.ps-card:hover .ps-acts,.ps-acts:focus-within{opacity:1}
.ps-acts button{all:unset;cursor:pointer;display:grid;place-items:center;text-align:center;padding:0 8px;
  font-size:12.5px;font-weight:600;color:#fff;background:rgba(8,11,16,.6)}
.ps-acts .ps-me{border-right:1px solid rgba(255,255,255,.2)}
.ps-acts .ps-me:hover,.ps-acts .ps-me:focus-visible{background:rgba(7,148,252,.78)}
.ps-acts .ps-all:hover,.ps-acts .ps-all:focus-visible{background:rgba(91,46,242,.85)}
.ps-in.pop{animation:ps-pop .6s cubic-bezier(.2,.9,.3,1.2)}
@keyframes ps-pop{0%{transform:translateX(44px) scale(.7);opacity:0}60%{transform:translateX(-4px) scale(1.04);opacity:1}100%{transform:none;opacity:1}}
.picstack.min .ps-deck{display:none}
@media (prefers-reduced-motion:reduce){ .ps-in.pop{animation:none} .ps-card,.ps-deck{transition:none} }
/* No hover on a touch screen: the two halves are always showing. */
@media (hover:none){ .ps-acts{opacity:.95} }
@media (hover:hover) and (pointer:fine){
  .imgspot .isp-bar{position:absolute;left:50%;bottom:14px;transform:translateX(-50%);z-index:2;
    max-width:calc(100% - 28px);padding:6px 6px 6px 14px;border-radius:12px;
    background:rgba(8,11,16,.86);border:1px solid rgba(255,255,255,.16);box-shadow:0 8px 28px rgba(0,0,0,.45);
    opacity:0;transition:opacity .2s ease}
  .imgspot:hover .isp-bar,.imgspot.barshow .isp-bar,.imgspot .isp-bar:focus-within{opacity:1}
  .imgspot .isp-bar .isp-cap{color:#e9edff}
  .imgspot .isp-bar .ghosty{color:#e9edff;border-color:rgba(255,255,255,.28)}
  .imgspot .isp-bar .ispfollow.on{border-color:#2BD9A6;color:#fff}
  .imgspot .isp-bar .ispfollow.on::before{background:#2BD9A6}
  #app.pinover .imgspot .isp-bar{display:none}
}
/* The picture alone, filling the screen, for whoever pressed Full screen. */
.imgspot:fullscreen{background:#05070a;padding:16px;gap:10px;justify-content:center}
.imgspot:fullscreen .isp-cap,.imgspot:fullscreen .ghosty{color:#e9edff;border-color:rgba(255,255,255,.25)}
/* An upright phone: the picture on top at its own height, the faces below it in the
   ordinary grid (renderGrid's `stacked`), rather than a strip under a lot of nothing. */
#app.stacked .imgspot{flex:0 0 auto;padding-top:0}
#app.stacked .imgspot .isp-bar{gap:6px}

.imgspot[hidden]{display:none}
.imgspot .isp-frame{position:relative;display:block;line-height:0;flex:0 0 auto;max-width:100%;
  touch-action:none;cursor:crosshair}
.imgspot img{display:block;max-width:100%;border-radius:14px;
  border:1px solid rgba(255,255,255,.14);box-shadow:0 24px 80px rgba(0,0,0,.6);background:#05070a}
/* The highlighter's surface, exactly over the picture. */
.imgspot .isp-ink{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;
  border-radius:14px}
.imgspot .isp-bar{display:flex;align-items:center;gap:8px;flex-wrap:nowrap;justify-content:center;
  flex:0 0 auto;max-width:100%;line-height:1.35}
.imgspot .isp-bar .btn{padding:5px 10px;font-size:12.5px;white-space:nowrap;flex:0 0 auto}
.imgspot .isp-cap{color:var(--ink);font-size:13px;min-width:0;max-width:60ch;text-align:center;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* Was a hardcoded light hex, which is right on the dark overlay and invisible on the
   light one. Tokens follow the theme. */
.imgspot .ghosty{background:none;border:1px solid var(--line);color:var(--ink)}

/* the name chip carries the person's colour — a light border, as asked */
.tile .chip{border:1px solid var(--who, var(--line))}

/* who is looking at which pane: a dot per person on the tab itself — under the name, in
   the tab's bottom padding, so it takes no width from the row; small, with a faint glow;
   four at most, the fourth place a "+N" (paintWhoDots). Beside the name, eight of them
   made the tab eight dots wider and every name in the row was cut to pay for it. */
.tabs-top button{position:relative}
.whodots{position:absolute;left:50%;bottom:2px;transform:translateX(-50%);display:flex;align-items:center;gap:2px;
  margin:0;line-height:1;white-space:nowrap}
.whodots i{width:4px;height:4px;border-radius:50%;background:var(--d,#8aa);box-shadow:0 0 3px var(--d,#8aa);flex:none}
.whodots b{font:600 8px/8px var(--mono);color:var(--mid);margin-left:1px;letter-spacing:0}

/* On a phone the view toggle floats over the video like the self-view does, instead of
   sitting in the bar — one more control in that row is what wraps it to a second line
   and knocks the whole menu down. */
@media (max-width:900px){
  #viewBtn{position:fixed;right:58px;top:calc(var(--vtop,0px) + 10px);z-index:15;
    width:38px;height:38px;border-radius:11px;background:rgba(5,8,23,.72);
    backdrop-filter:blur(8px);border:1px solid rgba(255,255,255,.14)}
}


/* ───────── overlays on the video: theme, and the view toggle ─────────
   Controls that change how YOU see the room sit over the room, top-right — they never
   resize the video and never widen the control bar into wrapping. */
.stagebtn{position:absolute;right:12px;top:12px;z-index:9;width:36px;height:36px;
  border-radius:11px;background:rgba(8,11,16,.62);backdrop-filter:blur(8px);
  border:1px solid rgba(255,255,255,.16);color:#EAF0FF;font-size:15px;cursor:pointer}
.stagebtn:hover{border-color:rgba(255,255,255,.4)}
#app.presenting .stagebtn{top:12px}
@media (max-width:900px){
  /* The theme button takes the corner and the view toggle sits inboard of it. It used
     to be the other way round, which left the sun floating 60px short of the corner
     whenever the view toggle was not rendered — and in a two-person call it usually
     is not, so the gap read as the icon being misplaced. The corner belongs to the
     control that is always there. */
  .stagebtn{top:calc(var(--vtop,0px) + 10px);right:12px;position:fixed}
}

/* The Clip past icon draws with strokes like every other bar icon — an unstyled SVG
   path fills itself solid black, which is the dark blob Jack saw in light mode. */
#pastBtn svg{fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
#viewBtn svg{fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}

/* The record choice: one small popover, two honest options. */
.recpop{position:absolute;bottom:calc(100% + 10px);left:50%;transform:translateX(-50%);
  z-index:30;display:flex;flex-direction:column;gap:6px;padding:8px;border-radius:12px;
  background:var(--panel);border:1px solid var(--line);box-shadow:0 16px 44px rgba(0,0,0,.45);
  white-space:nowrap}
.recpop[hidden]{display:none}
.recpop button{all:unset;cursor:pointer;font-size:13px;color:var(--ink);padding:8px 12px;
  border-radius:8px;display:flex;align-items:center;gap:8px}
.recpop button:hover{background:var(--field)}
.recpop button i{font-style:normal;color:var(--dim);font-size:11.5px}


/* ───────── the account widget, styled EVERYWHERE ─────────
   This lived in docs.css, which the homepage does not load — so the signed-in menu
   rendered there as an unstyled white box with the landing page's pale link colours
   bleeding in: white on white. The rule this earns: a component that can appear on
   any page gets its styles in the stylesheet every page loads, in theme tokens, once.
   The copy in docs.css stays and is identical, so doc pages are unchanged. */
.acct-btn{all:unset;cursor:pointer;display:flex;align-items:center;gap:8px;padding:5px 11px 5px 5px;
  border-radius:999px;border:1px solid var(--line);transition:.15s}
.acct-btn:hover{border-color:var(--blue)}
.acct-btn img{width:26px;height:26px;border-radius:50%;display:block}
.acct-btn .initial{width:26px;height:26px;border-radius:50%;background:var(--grad);color:#fff;
  display:grid;place-items:center;font-size:12.5px;font-weight:600}
.acct-btn span:last-child{font-size:13.5px;color:var(--ink);max-width:12ch;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.acct-menu{position:absolute;right:0;top:calc(100% + 8px);min-width:224px;z-index:60;
  background:var(--panel);border:1px solid var(--line);border-radius:14px;overflow:hidden;
  box-shadow:0 18px 44px -18px rgba(0,0,0,.8)}
.acct-menu[hidden]{display:none}
.acct-who{padding:13px 15px;border-bottom:1px solid var(--line);display:flex;flex-direction:column;gap:2px}
.acct-who b{font-size:13.5px;color:var(--ink)}
.acct-who span{font-size:12px;color:var(--dim);overflow:hidden;text-overflow:ellipsis}
.acct-menu a,.acct-menu button{display:block;width:100%;text-align:left;padding:11px 15px;
  font-size:13.5px;color:var(--mid);text-decoration:none;background:none;border:0;cursor:pointer;
  font:inherit;font-size:13.5px}
.acct-menu a:hover,.acct-menu button:hover{background:var(--panel2);color:var(--ink);text-decoration:none}
.acct-menu button{border-top:1px solid var(--line);color:var(--dim)}

/* the panel */
.tm-modal{position:fixed;inset:0;z-index:200;display:grid;place-items:center;padding:20px;
  background:rgba(3,5,16,.76);backdrop-filter:blur(8px);overflow-y:auto}
.tm-modal[hidden]{display:none}
body.tm-modal-open{overflow:hidden}
.tm-card{position:relative;width:min(440px,100%);background:var(--panel);border:1px solid var(--line);
  border-radius:20px;padding:30px 28px 24px;box-shadow:0 30px 80px -30px rgba(0,0,0,.9)}
.tm-x{position:absolute;right:14px;top:12px;all:unset;cursor:pointer;font-size:22px;line-height:1;
  color:var(--dim);padding:6px 10px;border-radius:9px}
.tm-x:hover{color:var(--ink)}
.tm-card h2{font-family:var(--display);font-size:22px;font-weight:600;letter-spacing:-.015em;
  margin:0 0 18px;color:var(--ink);max-width:16ch;line-height:1.25}
ul.tm-reasons{list-style:none;padding:0;margin:0 0 22px;display:flex;flex-direction:column;gap:13px}
ul.tm-reasons li{display:flex;flex-direction:column;gap:2px;padding-left:20px;position:relative}
ul.tm-reasons li::before{content:'';position:absolute;left:0;top:7px;width:8px;height:8px;
  border-radius:2px;background:var(--grad)}
ul.tm-reasons b{font-size:14px;color:var(--ink);font-weight:600;line-height:1.35}
ul.tm-reasons span{font-size:13px;color:var(--mid);line-height:1.5}
.tm-gbtn{display:flex;justify-content:center;min-height:44px}
.tm-fine{font-size:12.5px;color:var(--dim);margin:14px 0 0;text-align:center;line-height:1.5}
.tm-note{font-size:11.5px;color:var(--dim);margin:16px 0 0;text-align:center;line-height:1.55;
  padding-top:15px;border-top:1px solid var(--line)}
.tm-note a{color:var(--dim);text-decoration:underline}
.tm-note a:hover{color:var(--blue)}
@media (max-width:520px){ .tm-card{padding:26px 20px 20px} .tm-card h2{font-size:20px} }

/* And nothing from the landing page's own link styling may reach inside the menu —
   #gate a is pale-on-dark, which is exactly wrong on the menu's panel. */
#gate .acct-menu a{color:var(--mid)}
#gate .acct-menu a:hover{color:var(--ink)}
.signin-btn{cursor:pointer;font:inherit;font-size:13.5px;color:var(--mid);background:none;
  border:1px solid var(--line);border-radius:999px;padding:7px 15px}
.signin-btn:hover{color:var(--ink);border-color:var(--blue)}


/* the code pill's own copied state — green, then back */
#roomLabel.copied{border-color:var(--good);color:var(--good);background:rgba(14,124,87,.12);
  transition:background .15s,border-color .15s}
#roomLabel.copied .shic{color:var(--good)}


/* ───────── buttons are SOLID ─────────
   The gradient fill retires from every control — [stated] twice, "a well known vibe
   code signal". One confident blue, a readable label, a subtle lift on hover. The
   gradient survives only as ART: the brand bar, thumbnails, the progress fill —
   surfaces, never buttons. Appended last on purpose: equal specificity, later wins. */
.btn.go, .btn.go.wide, .primary, .growrow .primary, .past-card .primary,
.bk-go, .bk-join, .empty .btn.go, .docnav-right .btn.go, .btn.go.big{
  background:#1256E8; border:1px solid rgba(255,255,255,.22);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.22);
}
.btn.go:hover, .primary:hover, .bk-go:hover, .bk-join:hover, .btn.go.big:hover{
  background:#1B61F5;
}
:root[data-theme="light"] .btn.go, :root[data-theme="light"] .primary,
:root[data-theme="light"] .bk-go, :root[data-theme="light"] .bk-join{
  border-color:rgba(0,0,0,.08);
}


/* ───────── the phone's top edge, one visual system ─────────
   Two floating buttons with different shells plus two chips stacking on the same
   corner read as "boxes behind boxes". One shell for both buttons, one row; and when
   presenting, the REC chip steps below the presenter bar instead of on top of it. */
@media (max-width:900px){
  /* [stated] "top right see that this icon isnt fitting to the top right corner well".
     Two things were wrong. The backdrop was 62% opaque, so a bright camera showed
     through it and the button had no edge of its own — and it sat at the same 10px the
     tile does, which put it exactly on the tile's rounded corner where two borders ran
     through each other. Pushed in past the radius, and opaque enough to be a button
     sitting ON the video rather than a tint over it. */
  /* #themeBtn is named by id here because an earlier rule styles it by id, and an id
     beats a class no matter which sheet or which order — the same trap that put the
     dashboard rail 632px off-screen. Without it the theme button keeps a 34px width and
     a 9px radius while everything beside it is 36px and 11px. */
  #viewBtn, .stagebtn, #themeBtn.stagebtn, #railOpen{
    position:fixed;top:calc(var(--vtop,0px) + 16px);height:36px;
    border-radius:11px;background:rgba(8,11,16,.86);backdrop-filter:blur(10px);
    border:1px solid rgba(255,255,255,.18);color:#EAF0FF;z-index:15;
    display:grid;place-items:center;padding:0}
  #viewBtn, .stagebtn, #themeBtn.stagebtn{width:36px}
  .stagebtn, #themeBtn.stagebtn{right:16px} /* the corner — always present */
  #viewBtn{right:60px}                      /* inboard of it, when the room has one */
  /* Opposite them, on the same line and the same distance in, so the top of the screen
     reads as one row of controls rather than three things near the top. */
  #railOpen{left:16px;width:auto;padding:0 13px;font-size:12.5px}
  #app.presenting .recdots{top:52px}
  #app.presenting .spotbar{max-width:calc(100vw - 110px);overflow:hidden;
    text-overflow:ellipsis;white-space:nowrap}
}


/* The theme button floats over the stage's top-right; a tile's own pin/mute live in
   the tile's top-right. When one tile fills the stage those are the same pixels, and
   the overlay won silently — the buttons were visible and unclickable.

   That was first fixed by raising the whole TILE on hover, which traded one bug for a
   worse one: [stated] "hovering over my own video for some reason still causes the
   overlay transcription and light mode dark mode to disappear" — reported three times.
   A tile at z-index 20 is above the captions and the theme button, so pointing at your
   own face blanked the subtitles everyone was reading.

   The collision was already solved by the line below, which moves the tile's actions
   clear of the corner the overlay occupies. Position was enough; the stacking bump was
   redundant and destructive. Only the ACTIONS rise now, and only far enough to be
   clickable — the tile itself stays under the things drawn on top of it, which is what
   "drawn on top of it" is supposed to mean. */
#app.roomgrid #stagearea .tile:not(.selfpip) .tileacts{right:52px}
#stagearea .tile:hover .tileacts, #stagearea .tile:focus-within .tileacts{z-index:12}

/* ── an agenda arriving as a file ──────────────────────────────────────────
   Tokens, not hexes: this sits in the call's rail, which is dark, but the same
   stylesheet dresses the light pages and a literal colour here would be the same
   bug that put three black slabs on the recording page. */
.agdrop{margin-top:8px;padding:11px 13px;border:1px dashed var(--edge);border-radius:10px;
  background:var(--field);color:var(--dim);font-size:12px;line-height:1.5;cursor:pointer;
  display:flex;align-items:center;gap:8px;transition:border-color .12s,background .12s,color .12s}
.agdrop:hover{border-color:var(--blue);color:var(--mid)}
.agdrop.over{border-color:var(--blue);border-style:solid;background:rgba(7,148,252,.10);color:var(--ink)}
.agdrop.busy{border-style:solid;border-color:var(--blue);color:var(--mid)}
.agdrop.bad{border-color:var(--bad);color:var(--bad);border-style:solid}
.agdropnote{min-width:0;flex:1}

/* The word riding over the record dot, so the button says CLIP rather than leaving
   the universal record glyph to imply the whole meeting starts here — it does not,
   the meeting is already being kept. Stroke is cleared because .recdotic's dot is a
   filled circle and a stroked letterform at 5px is mud. */
.recdotic .clipword{fill:currentColor;stroke:none;font-family:var(--mono),ui-monospace,monospace;
  font-size:6.6px;font-weight:700;letter-spacing:.06em}

/* The slider that reaches backwards from a finished clip. Its range is set from what
   was actually banked, so it never offers seconds that do not exist.
   clipgrow, not growrow: .growrow is already the goals row further up this file, and
   a class reused across two features is how #rail and #0d1218 both went wrong today. */
.clipgrow{display:flex;align-items:center;gap:12px;margin-top:8px;flex-wrap:wrap}
.clipgrow input[type=range]{flex:1;min-width:140px;accent-color:var(--blue)}
.clipgrowamt{font-family:var(--mono);font-size:13px;color:var(--ink);min-width:46px;text-align:right}

/* ── off means off ─────────────────────────────────────────────────────────
   [stated] "use an X through the camera and the video when its turned off not just
   red". Red on its own is genuinely ambiguous — on half the products in the world a
   red microphone means it is live. The slash is the convention nobody misreads, so
   both icons carry one that is simply invisible until the thing is switched off. */
.ctlic{width:21px;height:21px;fill:none;stroke:currentColor;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round}
.ctlic .slash{opacity:0;stroke-width:2.1;transition:opacity .12s}
.ctl.off .ctlic .slash{opacity:1}
/* A slash reads as a slash only if it is not lost in the glyph it crosses, so the
   glyph steps back while it is there. */
.ctl.off .ctlic > use{opacity:.65}

/* The CC glyph: a caption bubble with lines in it, which reads as captions to somebody
   who has never been taught that "CC" means anything. */
.ccic{width:21px;height:21px;fill:none;stroke:currentColor;stroke-width:1.7;
  stroke-linecap:round;stroke-linejoin:round}
.ccic .tail{stroke-linejoin:round}
.ctl.on .ccic{stroke:var(--blue)}

/* [stated] "allow making an account from homepage like a signup button". Sign in is
   the quiet one; sign up is the one a first-time visitor is looking for, so it carries
   the weight. Both open the same panel — Google creates the account or returns you to
   it — so what differs is what a stranger believes about whether they are welcome. */
.signup-btn{cursor:pointer;font:inherit;font-size:13.5px;font-weight:600;color:#fff;
  /* --royal, not --acc: white on the brand blue is 3.0:1, which axe flagged on every
     page. The deeper blue is 6:1 and still the brand. */
  background:var(--royal);border:1px solid var(--royal);border-radius:9px;padding:7px 13px;
  margin-left:8px;white-space:nowrap}
.signup-btn:hover{background:var(--signal);border-color:var(--signal)}
@media (max-width:560px){ .signin-btn{display:none} }

/* A tabletop line has no known speaker. The label is set in italic so a reader can see
   at a glance that "Speaker 2" is a channel and "Sydney" is a person, without having
   to know what either means. */
.txline > b.sp-tabletop { font-style: italic; opacity: .82; }

/* Held while an invite link is being checked — see gbusy() in app.js. Not `disabled`,
   which on iOS greys the label to near-invisible; the point is that the button is
   still legible while it is not yet safe to press. */
.busy{pointer-events:none;opacity:.72;cursor:progress}

/* ───────── the clip trim bar ─────────
   Two handles over the clip already loaded in the sheet. Dragging seeks that video, so
   the frame on screen is the frame the cut lands on and nothing is fetched until Save.
   The handles are 26px wide over a 6px track: the track is what you read, the handle is
   what a thumb has to hit, and those are not the same size. */
.trimbar{position:relative;height:34px;margin:12px 0 8px;border-radius:8px;
  background:var(--sunk);border:1px solid var(--line);touch-action:none}
.trimheld{position:absolute;left:0;top:0;bottom:0;border-radius:7px 0 0 7px;
  background:repeating-linear-gradient(135deg,rgba(122,162,255,.16) 0 6px,transparent 6px 12px)}
.trimsel{position:absolute;top:0;bottom:0;background:rgba(58,124,255,.24);
  border-left:2px solid var(--blue);border-right:2px solid var(--blue)}
.trimh{position:absolute;top:50%;width:26px;height:38px;margin:-19px 0 0 -13px;padding:0;
  border:1px solid var(--line-bright,rgba(255,255,255,.34));border-radius:8px;
  background:var(--panel2);cursor:ew-resize;touch-action:none;z-index:2}
.trimh::after{content:'';position:absolute;left:50%;top:50%;width:2px;height:14px;
  margin:-7px 0 0 -1px;border-radius:1px;background:var(--mid)}
.trimh:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
.trimh:active{background:var(--blue);border-color:var(--blue)}
.trimrow{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.trimread{font-family:var(--mono);font-size:12.5px;color:var(--mid);flex:1 1 100%}
.trimrow .btn{flex:1 1 0;min-width:120px}
@media (max-width:700px){
  /* Bigger targets and a taller track: this is a drag done with a thumb on a moving
     train, not a mouse. */
  .trimbar{height:40px}
  .trimh{width:32px;height:46px;margin:-23px 0 0 -16px}
  .trimrow{justify-content:space-between}
  .trimrow .btn{flex:1;min-width:130px}
}

/* ───────── the rail header on a phone ─────────
   Five tabs plus Close plus ? do not fit on one 390px row at any size a person can
   read, so the row scrolled — and a tab you have to discover by swiping is a tab most
   people never find. "Chat" was sitting underneath the ? button.

   Two rows instead: the controls on top, the tabs beneath them with the full width to
   themselves. Nothing scrolls, and every tab is visible without being told to look. */
@media (max-width:700px){
  .rail-top{
    display:grid;
    grid-template-columns:auto 1fr auto;
    grid-template-areas:'close . help' 'tabs tabs tabs';
    row-gap:8px;
    align-items:center;
    padding:10px 12px 8px;
  }
  /* display:contents put these three in one row; with an explicit grid they are placed
     by name instead, so Close still leads and ? still ends — the arrangement Jack asked
     for — without them competing for one line. */
  #railClose{grid-area:close;order:0;margin-right:0}
  #guideBtn{grid-area:help;order:0}
  .tabs-top{
    grid-area:tabs;
    overflow-x:visible;          /* nothing left to scroll */
    gap:4px;
    justify-content:space-between;
  }
  .tabs-top button{
    /* Natural widths plus an equal share of what is left, as in the rail's own container
       query above. `1 1 0` split the row evenly, and this rule — later in the file — kept
       undoing that fix on phones: "Workspace" and "Transcript" cut beside a "Chat" with
       room to spare (test/rail-tabs.mjs, at 320, 360 and 390). */
    flex:1 1 auto;
    min-width:0;
    padding:8px 4px;
    font-size:12px;
    text-align:center;
    overflow:hidden;
    text-overflow:ellipsis;
  }
}


/* ───────── Notes & chat, as a control rather than a floating label ─────────
   [stated] "lets give notes and chat its own icon there" — there being the row of
   controls at the bottom. It used to be a text pill floating over the top-left of the
   video, which is a different kind of object from everything else that opens a panel,
   and it sat on top of whoever was in the top-left of the frame.

   It stays a labelled button on a wide screen, where there is room for the words. */
.notesic{display:none;width:20px;height:20px;fill:none;stroke:currentColor;
  stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
@media (max-width:900px){
  /* Into the bar, at the end of the control row, beside the other things that open
     something. display:contents on the wrapper so it can take its own place in the bar
     rather than travelling with the people-count it shares a div with. */
  .bar-right{display:contents}
  #railOpen{
    position:static !important; left:auto; top:auto; order:2; margin-left:2px;
    width:38px; height:38px; padding:0; display:grid; place-items:center;
    border-radius:11px; background:var(--panel2); border:1px solid var(--line);
    color:var(--ink); font-size:0; backdrop-filter:none;
  }
  #app.norail #railOpen{display:grid}
  #railOpen > span{display:none}
  #railOpen .notesic{display:block}
  /* The unread mark has to survive losing the text it used to sit beside. */
  #railOpen.hasunread::after{content:'';position:absolute;top:6px;right:6px;width:7px;
    height:7px;border-radius:50%;background:var(--blue);box-shadow:0 0 0 2px var(--panel)}
  #railOpen{position:relative !important}
}

/* ───────── the listening dot's glow was being clipped ─────────
   A box-shadow drawn OUTSIDE an element is cut off by any ancestor that clips, and
   .bar-left is overflow:hidden on a phone so the code label could ellipsis. The glow
   is what says transcription is live, and half a glow reads as a rendering fault.
   The label no longer needs clipping — it was removed from the bar — so the clip goes
   and the dot keeps its full halo. */
@media (max-width:900px){
  .bar-left{overflow:visible}
  #bar{overflow:visible}
}

/* ───────── iOS zooms into any input under 16px ─────────
   Not a preference — Safari on iPhone magnifies the page whenever a focused field's
   text is smaller than 16px, and because the room is a position:fixed shell, that
   magnification scrolls its top clean out of view. Tapping the chat box left a blank
   white screen above the input with the tabs, the messages and the video all gone.

   16px everywhere a person types, on phones only. This is the documented way to stop
   it: there is no property that disables the zoom, and `user-scalable=no` would also
   take pinch-zoom away from people who need it. */
@media (max-width:900px){
  input[type=text], input[type=search], input[type=email], input[type=url],
  input[type=tel], input[type=number], input:not([type]), textarea, select,
  .rail-ask input, .chat-send input, .invite input, .linkrow2 input,
  textarea.f, input.f, select.f{
    font-size:16px;
  }
}

/* ═══════════════════════ Legal mode · the Document pane ═══════════════════
   The draft on everyone's screen, the words lit up as Counsel reads them, and the
   redlines each party accepts or declines. One pane, driven by state.legal. */
#docPane{gap:12px}
.doc-top{display:flex;align-items:center;justify-content:space-between;gap:10px}
.doc-counsel{display:flex;align-items:center;gap:10px;min-width:0}
.doc-badge{width:34px;height:34px;border-radius:10px;display:grid;place-items:center;background:var(--panel2);border:1px solid var(--line);font-size:17px;flex:none}
#docPane.on .doc-badge{border-color:var(--acc);box-shadow:0 0 0 3px color-mix(in srgb,var(--acc) 22%,transparent)}
.doc-state{display:flex;flex-direction:column;min-width:0}
.doc-state b{font-size:14px}
.doc-status{font-size:12px;color:var(--mid);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.doc-ctl{display:flex;gap:6px;flex:none}
.doc-disclaim{margin:0;font-size:12px;line-height:1.5;color:var(--dim)}
.doc-parties{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.doc-party{background:var(--panel2);border:1px solid var(--line);border-radius:12px;padding:8px 10px;display:flex;flex-direction:column;gap:4px;min-width:0}
.doc-party b{font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:var(--dim)}
.doc-party span{font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.doc-party.me{border-color:var(--acc)}
.doc-party.empty span{color:var(--dim)}
.doc-party select{background:var(--panel);color:var(--ink);border:1px solid var(--line);border-radius:8px;padding:5px 7px;font-size:13px;max-width:100%}
.doc-caption{font-size:13.5px;line-height:1.5;color:var(--ink);background:linear-gradient(160deg,var(--sunk2),var(--sunk));border:1px solid var(--line);border-left:3px solid var(--acc);border-radius:10px;padding:8px 11px}
.doc-caption[hidden]{display:none}
.doc-row{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-top:8px}
.doc-row .btn,.doc-row label.btn{cursor:pointer}
.doc-h3{margin:16px 0 6px!important}
.doc-paste{width:100%;box-sizing:border-box;background:var(--panel);color:var(--ink);border:1px solid var(--line);border-radius:10px;padding:9px 11px;font:inherit;font-size:13px;line-height:1.5;resize:vertical;margin:8px 0}
.doc-head{display:flex;align-items:flex-start;justify-content:space-between;gap:10px;flex-wrap:wrap}
.doc-title h2{margin:0;font-size:17px;line-height:1.3}
.doc-title .muted{font-size:12px}
.doc-tools{display:flex;gap:2px;flex-wrap:wrap}
.doc-tools .ghost,.doc-tools label.ghost{font-size:12px;padding:4px 8px;cursor:pointer;text-decoration:none}
.doc-body{display:flex;flex-direction:column;gap:10px}
.doc-sec{background:var(--panel2);border:1px solid var(--line);border-radius:12px;padding:10px 12px;transition:border-color .25s,box-shadow .25s}
.doc-sec.reading{border-color:var(--acc);box-shadow:0 0 0 3px color-mix(in srgb,var(--acc) 18%,transparent)}
.doc-sec-head{display:flex;align-items:baseline;gap:7px;flex-wrap:wrap}
.doc-sec-head h4{margin:0;font-size:13.5px;flex:1;min-width:0}
.doc-num{font-size:12px;color:var(--dim);font-variant-numeric:tabular-nums}
.doc-agreed{font-size:11px;color:var(--good);border:1px solid color-mix(in srgb,var(--good) 45%,transparent);border-radius:999px;padding:1px 7px}
.doc-agreed.part{color:var(--warn);border-color:color-mix(in srgb,var(--warn) 45%,transparent)}
.doc-sec-acts{display:flex;gap:2px;margin-left:auto}
.doc-sec-acts .ghost{font-size:12px;padding:3px 7px}
.doc-text{font-size:13.5px;line-height:1.65;white-space:pre-wrap;margin-top:6px;color:var(--ink)}
.doc-text mark.doc-read{background:linear-gradient(90deg,color-mix(in srgb,var(--acc) 38%,transparent),color-mix(in srgb,var(--acc2) 30%,transparent));color:inherit;border-radius:3px;box-decoration-break:clone;-webkit-box-decoration-break:clone;transition:all .12s}
.doc-pos{display:flex;flex-wrap:wrap;gap:6px;margin-top:8px}
.doc-poschip{font-size:12px;line-height:1.45;border-radius:9px;padding:4px 8px;background:var(--panel);border:1px solid var(--line)}
.doc-poschip b{display:inline-block;min-width:14px;text-align:center;border-radius:5px;padding:0 4px;margin-right:5px;font-size:11px;color:#fff;background:var(--acc)}
.doc-poschip.B b{background:var(--acc2)}
.doc-props{border-color:var(--warn)}
.doc-prop{border-top:1px solid var(--line);padding:10px 0}
.doc-prop:first-of-type{border-top:0;padding-top:4px}
.doc-prop-title{display:flex;gap:7px;align-items:baseline;font-size:13.5px}
.doc-prop-title b{font-size:11px;text-transform:uppercase;letter-spacing:.07em;color:var(--warn)}
.doc-prop-why{margin:5px 0 7px;font-size:12.5px;color:var(--mid);line-height:1.5}
.doc-diff{font-size:13px;line-height:1.6;white-space:pre-wrap;background:var(--panel);border:1px solid var(--line);border-radius:9px;padding:8px 10px}
.doc-diff del{background:color-mix(in srgb,var(--bad) 22%,transparent);text-decoration:line-through;text-decoration-color:var(--bad);border-radius:3px}
.doc-diff ins{background:color-mix(in srgb,var(--good) 24%,transparent);text-decoration:none;border-radius:3px}
.doc-prop-row{display:flex;gap:7px;align-items:center;flex-wrap:wrap;margin-top:8px}
.doc-acc{font-size:11.5px;color:var(--dim);border:1px solid var(--line);border-radius:999px;padding:2px 8px}
.doc-acc.yes{color:var(--good);border-color:color-mix(in srgb,var(--good) 45%,transparent)}
.doc-prop-row .btn{padding:6px 11px;font-size:12.5px;margin-left:auto}
.doc-prop-row .btn + .btn{margin-left:0}
.doc-decided{font-size:12.5px;color:var(--mid);padding:6px 10px;border-radius:9px;background:var(--panel2);border:1px solid var(--line)}
.doc-decided.applied{color:var(--good)}
.doc-ask{display:flex;gap:8px;position:sticky;bottom:0;background:var(--panel);padding-top:6px}
.doc-ask input{flex:1;min-width:0;background:var(--panel2);color:var(--ink);border:1px solid var(--line);border-radius:10px;padding:9px 11px;font:inherit;font-size:13px}
.doc-ask input:disabled{opacity:.6}
#railTabs .dcount{display:inline-block;min-width:16px;height:16px;line-height:16px;border-radius:8px;background:var(--warn);color:#000;font-size:10.5px;font-weight:700;text-align:center;margin-left:5px;padding:0 4px;vertical-align:1px}
#railTabs .dcount[hidden]{display:none}
.doc-empty .btn{cursor:pointer}

/* ───────── captions while a screen or a picture holds the stage ─────────
   The pip has moved up above the strip, so the pip-clearing offset would put the
   captions on top of the faces in the strip. Above the strip instead, everywhere. */
#app.strip .captions{bottom:calc(var(--barpad,0px) + var(--striph,118px) + 26px)}
#app.strip.imgstage .captions{bottom:calc(var(--barpad,0px) + var(--striph,118px) + 72px)}

/* ───────── a phone held sideways ─────────
   As wide as a laptop and a third as tall, so the width rules call it a laptop and the
   height rules do not exist — JG's iPhone in landscape: a self picture taller than
   half the stage, a strip as tall as a third of it, captions floating in the middle.
   `pointer:coarse` keeps a short laptop window out of this. */
@media (max-height:520px) and (pointer:coarse){
  /* top and sides only: on a phone-width screen the bottom padding is the control
     bar's reservation (above), and a shorthand here silently threw it away */
  #stage{padding-top:6px;padding-left:6px;padding-right:6px;--striph:68px}
  #grid{gap:6px}
  #app.strip #grid{height:76px}
  /* the self picture: a corner, measured against the height that is scarce */
  #stagearea .tile.selfpip{right:8px;bottom:8px;width:auto;height:26vh;max-height:120px;min-height:64px;
    max-width:none;min-width:0;aspect-ratio:16/9}
  #stagearea .tile.selfpip:has(video.portrait){aspect-ratio:3/4}
  #stagearea .tile.selfpip .chip{font-size:9px;padding:1px 5px}
  .tile .chip{font-size:11px;padding:2px 6px;left:6px;bottom:6px}
  #app .captions,#app.haspip .captions,#app.focusmode .captions{bottom:calc(var(--barpad,0px) + 26vh + 20px)}
  #app.strip .captions{bottom:calc(var(--barpad,0px) + var(--striph) + 16px)}
  #app.strip.imgstage .captions{bottom:calc(var(--barpad,0px) + var(--striph) + 52px)}
  .cap-pill{font-size:12.5px;padding:5px 9px}
  .imgspot{gap:6px;padding-top:0}
  /* Three bands do not fit in 300px: while a picture is up over a shared screen the
     screen steps aside here (it is back the moment the picture closes). */
  #app.presenting.imgstage:not(.pinover) .spotlight{display:none}
  #app.strip .tile .whereat{display:none}
  .imgspot .isp-bar .btn{padding:4px 9px;font-size:12px}
  /* A phone's width cannot hold a caption and three buttons on one line: the caption
     gets its own, the buttons share the next. */
  .imgspot .isp-bar{flex-wrap:wrap}
  .imgspot .isp-cap{font-size:12px;flex:1 0 100%;max-width:100%}
  .recdots{top:8px;left:8px}
  .stagebtn{top:8px;right:8px}
  #spotlight .spotbar{top:8px;left:8px;font-size:11px;padding:4px 8px}
}
@media (max-height:520px) and (pointer:coarse) and (min-width:901px){
  #stage{padding-bottom:6px}   /* the bar is a grid row here, nothing to reserve */
}

/* ───────── a tile whose picture is not there, and why ─────────
   [stated, 2026-10-13] "IF SOMEONES CAMERA IS SWITCHED OFF ITS NOT OBVIOUS RELATIVE TO
   IF ITS JUST BROKEN". One line under the initial says which (paintCam in app.js):
   "Camera off" and "Camera paused" are calm — nothing is wrong; "Connecting…" and
   "Starting video…" spin; "Can't reach …" and "Camera on · no picture" are amber —
   something is. The tile is the stage colour in both themes, so the line is drawn for
   that ground rather than for the page's.

   The initial and its line are one centred stack: the initial moves up by half the
   line, the line sits 8px under it. Short tiles — the strip, the corner picture, a
   phone's two-up grid in landscape — put the line along the top instead. */
.tile .linkstate,.tile .camstate{position:absolute;left:50%;top:calc(50% + var(--av,76px) / 2 - 8px);
  transform:translateX(-50%);z-index:4;max-width:calc(100% - 20px);box-sizing:border-box;
  padding:4px 11px;border-radius:999px;background:rgba(8,11,24,.78);border:1px solid rgba(255,255,255,.14);
  color:#E4E9F7;font-size:12px;line-height:1.3;text-align:center;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tile .linkstate{pointer-events:none}
.tile .camstate{display:inline-flex;align-items:center;gap:6px;padding-left:9px}
.tile .camstate span{overflow:hidden;text-overflow:ellipsis}
.tile .camstate svg{width:14px;height:14px;flex:none;fill:none;stroke:currentColor;stroke-width:1.8;
  stroke-linecap:round;stroke-linejoin:round}
.tile .camstate .spin,.tile .avatar::after{border-radius:50%;animation:tmspin .9s linear infinite}
.tile .camstate .spin{width:11px;height:11px;flex:none;border:2px solid rgba(255,255,255,.22);border-top-color:#E4E9F7}
@keyframes tmspin{to{transform:rotate(360deg)}}
/* one line at a time: a link that is down is the thing to say */
.tile.unlinked .camstate{display:none}
#app:not(.strip) .tile:not(.short):not(.instrip):not(.compactchip):has(> .camstate) .avatar,
#app:not(.strip) .tile.unlinked:not(.short):not(.instrip):not(.compactchip) .avatar{transform:translateY(-16px)}
.tile.unlinked .avatar{opacity:.8}
/* Connecting, or the camera starting: a ring turns round the initial. */
.tile.unlinked:not(.unreachable) .avatar::after,.tile[data-vstate="waiting"] .avatar::after{
  content:'';position:absolute;inset:-6px;border:2px solid transparent;border-top-color:var(--who,#9fb0d8)}
/* Something is wrong: amber, still and plain. */
.tile.unreachable .avatar,.tile[data-vstate="nopicture"] .avatar,.tile[data-vstate="trouble"] .avatar{box-shadow:0 0 0 2px rgba(255,176,32,.85)}
.tile.unreachable .linkstate,.tile[data-vstate="nopicture"] .camstate,.tile[data-vstate="trouble"] .camstate{color:#FFE2B8;
  border-color:rgba(255,176,32,.5);background:rgba(40,24,4,.82)}
/* Switched off or paused on purpose: a quiet wash of their colour behind the initial. */
.tile[data-vstate="off"],.tile[data-vstate="paused"]{
  background:radial-gradient(58% 62% at 50% 44%, color-mix(in srgb, var(--who,#5b6b9a) 15%, transparent), transparent 72%), #0e1218}
.tile.short .linkstate,.tile.short .camstate{top:6px;font-size:10.5px;padding:3px 8px;gap:4px}
.tile.short .camstate svg{width:11px;height:11px}
.tile.short .camstate .spin{width:8px;height:8px;border-width:1.5px}
/* A thumbnail has no room under the initial, and its name chip owns the bottom —
   the line goes along the top. */
#stagearea.focused .tile.instrip .linkstate,#app.strip #stagearea .tile .linkstate,
#stagearea.focused .tile.instrip .camstate,#app.strip #stagearea .tile .camstate{top:6px;font-size:10.5px;padding:3px 8px}
@media (prefers-reduced-motion:reduce){
  .tile .camstate .spin,.tile .avatar::after,.tile .chip .st .spin{animation:none}
  .tile .avatar{transition:none}
}
/* [stated, 2026-10-30] "Fix this part where its overlapped". A small tile — a thumbnail
   in the strip, a narrow or short grid cell, the corner picture — has no room for the
   line under the initial: in a strip of eleven it was cut to "Cam…" and "Can't r…" and
   sat on top of two other labels. There the state is an icon at the front of the name
   chip, the sentence its tooltip; the line itself is for tiles big enough to read it. */
.tile .chip .st{display:none}
.tile.compactchip .chip .st,.tile.short .chip .st,#stagearea.focused .tile.instrip .chip .st,
#app.strip #stagearea .tile .chip .st,#stagearea .tile.selfpip .chip .st{
  display:inline-flex;align-items:center;justify-content:center;flex:none;width:13px;height:13px;color:#E4E9F7}
.tile .chip .st svg{width:13px;height:13px;fill:none;stroke:currentColor;stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round}
.tile .chip .st .spin{width:9px;height:9px;border-radius:50%;border:1.6px solid rgba(255,255,255,.25);border-top-color:#E4E9F7;
  animation:tmspin .9s linear infinite}
.tile .chip .st[data-k="unreachable"],.tile .chip .st[data-k="nopicture"],.tile .chip .st[data-k="trouble"]{color:#FFC46B}
.tile.compactchip .camstate,.tile.compactchip .linkstate,.tile.short .camstate,.tile.short .linkstate,
#stagearea.focused .tile.instrip .camstate,#stagearea.focused .tile.instrip .linkstate,
#app.strip #stagearea .tile .camstate,#app.strip #stagearea .tile .linkstate,
#stagearea .tile.selfpip .camstate,#stagearea .tile.selfpip .linkstate{display:none}
/* In a short tile the initial sits in the space above the name chip, not behind it. */
.tile.short:not(.selfpip) .avatar{transform:translateY(-8px)}
/* A name that does not fit ends in an ellipsis inside its chip, never past the tile. */
.tile .chip{max-width:calc(100% - 2 * var(--chip-inset,10px));box-sizing:border-box}
.tile .chip .nm{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ───────── feedback, from inside the call ─────────
   A labelled button in the bar on a laptop — the words, not an icon nobody reads — and
   in the panel and the settings sheet everywhere, because a phone's bar has no room
   left. The sheet keeps you in the call. */
.fbbtn{display:inline-flex;align-items:center;gap:7px}
.fbic{width:17px;height:17px;fill:none;stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round;flex:none}
.fbbtn:hover .fbic{color:var(--blue)}
.fbrail{font-size:12px;border:1px solid var(--line);border-radius:9px;padding:5px 10px}
.fbrail:hover{border-color:var(--blue);color:var(--ink)}
@media (max-width:900px){ #fbBtn{display:none} }
/* Narrow screens: the picture's caption on a line of its own, the buttons on the next. */
@media (max-width:900px){
  .imgspot .isp-bar{flex-wrap:wrap}
  .imgspot .isp-cap{flex:1 0 100%;max-width:100%}
}
.fbrow{display:grid;gap:3px;width:100%;text-align:left;margin:14px 0 6px;padding:12px 14px;border-radius:12px;
  background:var(--panel2);border:1px solid var(--line);color:var(--ink);cursor:pointer}
.fbrow b{font-size:14px}
.fbrow span{font-size:12.5px;color:var(--mid)}
.fbrow:hover{border-color:var(--blue)}
.fbform{display:grid;gap:12px;margin:16px 0 4px}
.fbkinds{display:flex;flex-wrap:wrap;gap:8px}
.fbk{padding:7px 13px;border-radius:999px;border:1px solid var(--line);background:var(--panel2);color:var(--mid);font-size:13px;cursor:pointer}
.fbk.on{border-color:var(--blue);color:var(--ink);box-shadow:inset 0 0 0 1px var(--blue)}
.fbtext{width:100%;box-sizing:border-box;min-height:120px;resize:vertical;padding:12px 14px;border-radius:12px;
  border:1px solid var(--line);background:var(--panel);color:var(--ink);font:inherit;font-size:15px;line-height:1.5}
.fbtext:focus-visible{outline:2px solid var(--blue);outline-offset:1px;border-color:var(--blue)}
.fbfix{display:flex;align-items:center;gap:9px;font-size:13.5px;color:var(--ink);cursor:pointer}
.fbfix input{width:17px;height:17px;accent-color:var(--blue);flex:none}
.fbform .btn.go{justify-self:start;padding:10px 20px;font-size:14px}
.fbout{margin:0;font-size:13px;color:var(--mid);min-height:1em}
/* Attach a screenshot: the button, or the picture that will go with it and a × to drop it. */
.fbshot{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px}
.fbshot .fbshotbtn{padding:7px 13px;font-size:13px}
.fbshot .fbshotbtn::before{content:'';width:14px;height:14px;margin-right:7px;display:inline-block;vertical-align:-2px;background:currentColor;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 8h3l2-3h6l2 3h3v11H4z'/%3E%3Ccircle cx='12' cy='13' r='3.5'/%3E%3C/svg%3E") center/contain no-repeat;
          mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 8h3l2-3h6l2 3h3v11H4z'/%3E%3Ccircle cx='12' cy='13' r='3.5'/%3E%3C/svg%3E") center/contain no-repeat}
.fbshotprev{position:relative;display:inline-block;line-height:0}
.fbshotprev[hidden]{display:none}
.fbshotprev img{max-width:220px;max-height:124px;border-radius:10px;border:1px solid var(--line);object-fit:contain;background:var(--sunk)}
.fbshotx{all:unset;box-sizing:border-box;position:absolute;top:-8px;right:-8px;width:22px;height:22px;border-radius:50%;display:grid;place-items:center;
  cursor:pointer;font-size:15px;line-height:1;color:#fff;background:#3a3f4b;border:1px solid rgba(255,255,255,.25)}
.fbshotx:hover,.fbshotx:focus-visible{background:#e5484d}
.fbshotnote{font-size:12px;color:var(--dim)}

/* A task handed to someone's own agent (app.js handoffCard), and what their agent says back. */
.cm.handoff{border-left:3px solid var(--blue);padding-left:10px}
.cm.handoff .ho-acts{display:flex;flex-wrap:wrap;gap:8px;margin:8px 0 2px}
.cm.handoff .ho-acts .btn{padding:6px 12px;font-size:12.5px}
.cm.handoff .ho-link{font-size:12.5px}
.cm.agentnote{border-left:3px solid #2FD39A;padding-left:10px}
.fbdone{color:var(--mid);line-height:1.55;word-break:break-word}
.fbdone a{color:var(--blue)}
.fbai{margin-top:16px;padding:14px 16px;border-radius:12px;background:var(--panel2);border:1px solid var(--line);
  font-size:13px;line-height:1.6;color:var(--mid)}
.fbai b{color:var(--ink)}
.fbai i{color:var(--ink);font-style:normal}
.fbai code{font-size:12px;padding:1px 5px;border-radius:5px;background:var(--panel);border:1px solid var(--line);color:var(--ink)}
.fbai a{color:var(--blue)}
.fbai .fbpr{display:block;margin-top:8px;color:var(--ink)}
/* The panel's Feedback button keeps its own width beside "?" — in the two-row rail
   header it would otherwise take the empty middle column and stretch across it. */
@container rail (max-width:600px){
  #fbRail{grid-area:1 / 2;justify-self:end;margin-right:6px}
}
@media (max-width:900px){ #fbRail{order:1} }
/* Several people pinned: each is sized and offset inside the stage's one cell by
   fitTiles (renderGrid gives them all the stage row), so they align to its corner. */
#stagearea.focused.multistage .tile.stage:not(.selfpip){justify-self:start;align-self:start}

/* Left out of the record at their own request — said on their tile, to everyone. */
.tile .norecmark{position:absolute;top:8px;left:8px;z-index:4;padding:3px 8px;border-radius:999px;
  background:rgba(8,11,24,.78);border:1px solid rgba(255,255,255,.18);color:#E4E9F7;
  font-size:11px;letter-spacing:.02em;pointer-events:none}
.tile .norecmark::before{content:'';display:inline-block;width:7px;height:7px;margin-right:6px;border-radius:50%;
  background:transparent;border:1.5px solid #E4E9F7;vertical-align:0}

/* The facilitator is the shared visual field, not an optional side note. Video
   remains in the native filmstrip; screen sharing keeps its existing precedence. */
#app.facstage #stage{--striph:84px;gap:9px;background:var(--bg)}
#app.facstage.strip #grid{height:92px;flex:0 0 92px}
#app.facstage #stagearea{min-height:0}
#app.facstage #grid .tile.me{display:none}
#app.facstage.facsolo #grid{display:none}
.fac-canvas{display:flex;flex-direction:column;flex:1 1 auto;min-width:0;min-height:0;position:relative;overflow:hidden;border:1px solid var(--line);border-radius:16px;background:var(--panel);box-shadow:var(--shadow)}
.fac-canvas-head{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:17px 22px;border-bottom:1px solid var(--line);flex:0 0 auto;background:var(--panel)}
.fac-canvas-brand{display:flex;align-items:center;gap:11px;min-width:0}
.fac-canvas-symbol{width:34px;height:34px;display:grid;place-items:center;border-radius:50%;background:var(--grad);color:var(--cloud);font-size:25px;flex:0 0 auto}
.fac-canvas-brand b{display:block;font:600 13px/1.4 var(--display);color:var(--ink)}
.fac-canvas-status{display:block;font-size:10px;line-height:1.5;color:var(--mid);margin-top:3px}
.fac-canvas-actions{display:flex;flex-wrap:wrap;justify-content:flex-end;max-width:100%;gap:6px;flex:0 0 auto;align-items:center}
.fac-canvas-btn{border:1px solid var(--edge);border-radius:8px;padding:8px 11px;background:var(--panel2);color:var(--ink);font:500 11px/1.3 Inter,system-ui,sans-serif;cursor:pointer;white-space:nowrap}
.fac-canvas-btn:hover{background:var(--hover);border-color:var(--blue)}
.fac-canvas-content{flex:1 1 auto;min-height:0;overflow:auto;padding:28px clamp(20px,4vw,64px) 30px;background:radial-gradient(ellipse at 100% 0, color-mix(in srgb,var(--violet) 8%,transparent),transparent 60%),var(--panel);overscroll-behavior:contain}
.fac-canvas-intention{display:flex;align-items:baseline;gap:15px;padding:0 0 20px;border-bottom:1px solid var(--line);color:var(--mid)}
.fac-canvas-intention>span{font:500 9px/1.5 var(--mono);letter-spacing:.12em;white-space:nowrap;color:var(--blue-ink)}
.fac-canvas-intention>p{font-size:13px;line-height:1.6;margin:0;color:var(--mid);overflow-wrap:anywhere}
.fac-canvas-current{max-width:960px;padding:30px 0 25px}
.fac-canvas-kicker{display:block;font:500 9px/1.6 var(--mono);letter-spacing:.12em;color:var(--blue-ink);margin-bottom:13px}
.fac-canvas-current h2{font:500 clamp(23px,2.6vw,40px)/1.3 var(--display);color:var(--ink);letter-spacing:-.035em;margin:0 0 18px;max-width:35ch;overflow-wrap:anywhere}
.fac-canvas-quote{font-size:11px;line-height:1.7;color:var(--mid);border-left:2px solid var(--line);padding:4px 0 4px 12px;margin:10px 0;max-width:80ch;overflow-wrap:anywhere}
.fac-canvas-quote cite{display:block;font-size:10px;color:var(--dim);font-style:normal;margin-top:3px}
.fac-canvas-map{padding-top:22px;display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,280px),1fr));gap:14px}
.fac-canvas-current+.fac-canvas-map{padding-top:0}
.fac-canvas-section{border:1px solid var(--line);border-radius:12px;padding:18px;min-width:0;background:var(--panel2)}
.fac-canvas-section h3{font:600 12px/1.5 var(--display);margin:0 0 12px;color:var(--ink)}
.fac-canvas-section[data-kind=perspectives]{border-top:2px solid var(--violet)}
.fac-canvas-section[data-kind=themes]{border-top:2px solid var(--blue)}
.fac-canvas-section[data-kind=questions],.fac-canvas-section[data-kind=hypotheses]{border-top:2px solid var(--warn)}
.fac-canvas-section[data-kind=next]{border-top:2px solid var(--good)}
.fac-canvas-item+ .fac-canvas-item{border-top:1px solid var(--line);padding-top:13px;margin-top:15px}
.fac-canvas-item>p{font-size:12px;line-height:1.8;color:var(--ink);margin:0;overflow-wrap:anywhere}
.fac-canvas-item .fac-canvas-quote{font-size:10px}
.fac-canvas-sources{display:flex;gap:8px;flex-wrap:wrap;margin:12px 0 0}
.fac-canvas-sources a{display:block;max-width:100%;font-size:10px;line-height:1.6;color:var(--blue-ink);border:1px solid var(--line);border-radius:6px;padding:5px 8px;text-decoration:none;overflow-wrap:anywhere}
.fac-canvas-sources a:hover{text-decoration:underline}
.fac-canvas-ask{border-top:1px solid var(--line);background:var(--panel);padding:14px 22px 12px;flex:0 0 auto}
.fac-canvas-ask-label{display:block;font-size:10px;line-height:1.5;color:var(--mid);margin-bottom:7px}
.fac-canvas-input-row{display:flex;gap:8px;align-items:stretch;min-width:0}
.fac-canvas-input-row input{flex:1 1 auto;min-width:0;background:var(--field);border:1px solid var(--edge);border-radius:9px;padding:11px 12px;color:var(--ink);font:13px/1.4 Inter,system-ui,sans-serif}
.fac-canvas-primary{flex:0 0 auto;border:0;border-radius:8px;padding:10px 20px;background:var(--grad);color:var(--cloud);font:600 12px/1.4 Inter,system-ui,sans-serif;cursor:pointer}
.fac-canvas-input-row button:disabled{opacity:.5;cursor:default}
.fac-canvas-foot{display:flex;justify-content:space-between;align-items:center;gap:12px;margin-top:9px;flex-wrap:wrap}
.fac-canvas-foot>span{font-size:9px;line-height:1.6;color:var(--dim)}
.fac-canvas-share{padding:0;border:0;background:transparent;color:var(--blue-ink);font:500 10px/1.6 Inter,system-ui,sans-serif;cursor:pointer;text-align:left}
.fac-canvas-restore{position:absolute;left:14px;top:14px;z-index:15;border:1px solid var(--edge);border-radius:10px;background:var(--panel);box-shadow:var(--shadow);padding:10px 14px;color:var(--ink);font:600 12px/1.5 Inter,system-ui,sans-serif;cursor:pointer}
.fac-canvas:fullscreen{background:var(--panel);border:0;border-radius:0;width:100vw;height:100dvh}
.fac-canvas button:focus-visible,.fac-canvas input:focus-visible,.fac-canvas a:focus-visible,.fac-canvas-restore:focus-visible{outline:2px solid var(--blue-ink);outline-offset:3px}
@media(max-width:1100px){.fac-canvas-head{padding:14px 18px}.fac-canvas-content{padding:22px}.fac-canvas-actions{gap:5px}.fac-canvas-btn{padding:8px 9px}}
@media(max-width:700px){#app.facstage #stage{--striph:64px;gap:6px}#app.facstage.strip #grid{height:70px;flex-basis:70px}.fac-canvas{border-radius:12px}.fac-canvas-head{padding:12px;gap:8px;align-items:flex-start;flex-wrap:wrap}.fac-canvas-brand{gap:8px}.fac-canvas-brand b{font-size:12px}.fac-canvas-symbol{width:28px;height:28px;font-size:21px}.fac-canvas-status{font-size:9px}.fac-canvas-actions{margin-left:auto}.fac-canvas-actions .fac-canvas-btn{font-size:10px;padding:6px 9px}.fac-canvas-content{padding:18px 16px 22px}.fac-canvas-intention{display:block;padding-bottom:15px}.fac-canvas-intention p{font-size:12px;margin-top:5px}.fac-canvas-current{padding:23px 0 16px}.fac-canvas-current h2{font-size:25px;line-height:1.35}.fac-canvas-map{grid-template-columns:1fr;gap:10px}.fac-canvas-section{padding:14px}.fac-canvas-ask{padding:11px 12px}.fac-canvas-input-row{display:grid;grid-template-columns:minmax(0,1fr) auto auto;gap:6px}.fac-canvas-input-row input{grid-column:1/-1;font-size:16px;padding:9px 10px}.fac-canvas-input-row .fac-canvas-primary{text-align:left;font-size:11px;padding:9px 14px}.fac-canvas-input-row .fac-canvas-btn{font-size:10px;padding:9px}.fac-canvas-input-row .fac-stop{font-size:10px;padding:8px 10px}.fac-canvas-foot{gap:5px;margin-top:7px}.fac-canvas-foot>span{font-size:8px}.fac-canvas-share{font-size:9px}.fac-canvas-restore{left:10px;top:10px;padding:9px 12px;font-size:11px}}
@media(max-width:360px){.fac-canvas-head{padding:10px}.fac-canvas-actions{width:100%;margin-left:36px}.fac-canvas-content{padding:15px 12px}.fac-canvas-current h2{font-size:23px}.fac-canvas-quote{font-size:10px}.fac-canvas-foot>span{display:none}}
/* Captions keep their own row above the question box so live speech never covers
   Ask, Stop, or the checked quotes. No video node is moved for this. */
#app.facstage #captions{position:relative;left:auto;bottom:auto;transform:none;width:100%;max-width:100%;flex:0 0 auto;padding:0 18px;box-sizing:border-box}
#app.facstage #captions .cap-pill{font-size:12px;box-shadow:none;max-width:100%}
#app.facstage .recdots{top:auto;bottom:calc(var(--barpad,0px) + 20px);left:18px;z-index:12}
#app.facstage .fac-canvas-head{padding-right:54px}
@media(max-width:700px){#app.facstage #captions{padding:0 10px}#app.facstage #captions .cap-pill{font-size:11px;padding:5px 8px}#app.facstage .recdots{left:10px;bottom:calc(var(--barpad,0px) + 18px)}#app.facstage .fac-canvas-head{padding-right:42px}}


/* A thumbnail needs a thumbnail label, even in a wide desktop window. Keep the
   name and host status inside the picture; supplementary roles stay in the title. */
#app #grid .tile .chip{box-sizing:border-box;min-width:0;max-width:calc(100% - 2 * var(--chip-inset,6px));
  left:var(--chip-inset,6px);bottom:var(--chip-inset,6px);gap:.4em;
  font-size:var(--chip-font,12px);line-height:1.25;padding:.25em .6em}
#app #grid .tile .chip .nm{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
#app #grid .tile .chip .role{flex:none;font-size:.83em}
#app #grid .tile .chip .badge{flex:none;font-size:max(7px,.79em);padding:.25em .5em;margin-left:0}
#app #grid .tile .chip .star{flex:none;font-size:1em}
#app #grid .tile.compactchip .chip .role{display:none}

.fac-canvas-input-status{display:block;padding:0;border:0;background:transparent;text-align:left;color:var(--mid);font:10px/1.5 Inter,system-ui,sans-serif;margin-top:4px;cursor:pointer;text-decoration:underline;text-decoration-color:var(--line);text-underline-offset:3px}
.fac-history-toolbar{display:flex;justify-content:space-between;align-items:center;gap:12px}
.fac-history-toolbar h2{font:600 19px/1.4 var(--display);color:var(--ink);margin:0}
.fac-history-description{font-size:12px;line-height:1.7;color:var(--mid);max-width:75ch;margin:12px 0 20px}
.fac-history-entry{border:1px solid var(--line);border-radius:12px;padding:20px;background:var(--panel2);margin:16px 0}
.fac-history-entry p{font-size:13px;line-height:1.7;color:var(--ink);overflow-wrap:anywhere}
.fac-history-entry .fac-canvas-kicker{margin-bottom:12px}
.fac-history-card+.fac-history-card{border-top:1px solid var(--line);padding-top:12px;margin-top:16px}
.fac-history-card h3{font-size:11px;color:var(--mid);margin:0 0 6px}
@media(max-width:700px){.fac-canvas-input-status{font-size:9px}.fac-history-entry{padding:14px}.fac-history-toolbar h2{font-size:16px}}

/* [stated] Scored public observations stay visible without filling the canvas. */
.fac-observations{flex:0 0 auto;min-height:0;border-top:1px solid var(--edge);background:var(--panel);padding:10px 20px}
.fac-observations-head{display:flex;align-items:center;justify-content:space-between;gap:12px;font-size:12px;margin-bottom:7px}.fac-observations-head b{color:var(--ink)}.fac-observations-head>span{color:var(--dim);font-size:10px}
.fac-observations-list{max-height:150px;overflow:auto;overscroll-behavior:contain;scrollbar-width:thin}
.fac-observation{display:flex;gap:12px;padding:9px 0;border-top:1px solid var(--edge);align-items:flex-start}.fac-observation:first-child{border-top:0}.fac-observation>div{min-width:0;flex:1}.fac-observation p{font-size:13px;line-height:1.5;margin:0 0 4px;color:var(--ink);overflow-wrap:anywhere}
.fac-observation-score{flex:0 0 62px;border:1px solid var(--edge);background:var(--field);color:var(--dim);border-radius:8px;padding:7px 5px;text-align:center;font:600 12px/1.2 ui-monospace,monospace}.fac-observation-score.ready{color:var(--blue);border-color:var(--blue)}
.fac-observation-meta,.fac-observation-evidence{color:var(--dim);font-size:10px}.fac-observation-evidence summary{cursor:pointer;margin-top:5px}.fac-observation-evidence .fac-canvas-quote{font-size:11px;margin:6px 0}.fac-observation-empty{font-size:11px;color:var(--dim);margin:3px 0}.fac-speak-up{white-space:nowrap;border-color:var(--blue)}
@media(max-width:700px){.fac-observations{padding:8px 12px}.fac-observations-head{align-items:flex-start;gap:6px;font-size:11px}.fac-observations-head>span{font-size:9px;max-width:140px;text-align:right}.fac-observations-list{max-height:125px}.fac-observation{gap:8px}.fac-observation p{font-size:12px}.fac-observation-score{flex-basis:54px;font-size:11px}.fac-canvas-input-row{grid-template-columns:repeat(2,minmax(0,1fr))}.fac-canvas-input-row .fac-canvas-primary{text-align:center}.fac-canvas-input-row button{min-width:0}}

/* Saving the end of a recording on leave (app.js drainUpload). Over everything, calm,
   with the number that matters and a way out. */
.savewait{position:fixed;inset:0;z-index:9999;display:grid;place-items:center;padding:16px;
  background:color-mix(in srgb,var(--bg,#050817) 72%,transparent);backdrop-filter:blur(6px)}
.savecard{width:min(420px,100%);background:var(--panel);border:1px solid var(--line);border-radius:18px;
  padding:22px 22px 18px;box-shadow:0 24px 60px rgba(0,0,0,.35);display:flex;flex-direction:column;gap:10px}
.savecard b{font-family:var(--display);font-size:17px;color:var(--ink)}
.savesub{margin:0;font-size:14px;color:var(--mid);font-variant-numeric:tabular-nums}
.savebar{height:8px;border-radius:99px;background:var(--sunk);overflow:hidden}
.savebar i{display:block;height:100%;width:0;border-radius:inherit;background:var(--grad,linear-gradient(90deg,#0794FC,#5B2EF2));transition:width .35s ease}
.savefine{margin:0;font-size:12px;color:var(--dim);line-height:1.5}
.savego{all:unset;cursor:pointer;align-self:flex-start;font-size:12px;color:var(--dim);text-decoration:underline;text-underline-offset:3px}
.savego:hover{color:var(--bad,#E5484D)}

/* The leaving screen (app.js byeScreen): up the moment Leave is pressed, over the call
   (whose layers stop at 85) and under the sign-in panel a guest is offered (200). Opaque,
   because the call behind it is over. */
.byewait{position:fixed;inset:0;z-index:150;display:grid;place-items:center;padding:16px;background:var(--bg,#050817)}
.byecard{width:min(440px,100%);background:var(--panel);border:1px solid var(--line);border-radius:18px;
  padding:24px 24px 20px;box-shadow:0 24px 60px rgba(0,0,0,.28);display:flex;flex-direction:column;gap:10px}
.byekick{font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:var(--dim)}
.byetitle{font-family:var(--display);font-size:20px;line-height:1.25;color:var(--ink);overflow-wrap:anywhere}
.byefacts{margin:0;font-size:14px;color:var(--mid);font-variant-numeric:tabular-nums}
.byesave{display:flex;flex-direction:column;gap:8px;margin-top:4px}
.byesub{margin:0;font-size:14px;color:var(--ink);font-variant-numeric:tabular-nums}
.byenext{margin:2px 0 0;font-size:13px;color:var(--dim);line-height:1.5}
.byenext a{color:var(--ink)}
/* Going up, and how far not yet known (byeScreen `progress`): a stripe that moves rather
   than a bar stuck at nothing. Still, and faint, for reduced motion. */
.byecard .savebar.going i{width:32%;animation:byego 1.3s ease-in-out infinite}
@keyframes byego{from{transform:translateX(-100%)}to{transform:translateX(320%)}}
@media (prefers-reduced-motion:reduce){.byecard .savebar.going i{animation:none;width:100%;opacity:.35}}

/* Ova, answering in the chat (app.js ovaCard) and the Ask AI switch beside Send. */
.chat-send .aitoggle{white-space:nowrap}
.chat-send .aitoggle.on{background:var(--grad,linear-gradient(90deg,#0794FC,#5B2EF2));color:#fff;border-color:transparent}
.cm.ova{padding:10px 12px;border-radius:12px;background:color-mix(in srgb,var(--acc) 9%,var(--panel2,var(--panel)));
  border:1px solid color-mix(in srgb,var(--acc) 35%,var(--line));display:flex;flex-direction:column;gap:6px}
.ovahead{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px}
.ovaq{font-size:11.5px;color:var(--dim)}
.ovatext{font-size:13.5px;line-height:1.55;color:var(--ink)}
.ovaweb{border-top:1px dashed var(--line);padding-top:6px}
.ovaweb b{font-size:11px;letter-spacing:.06em;text-transform:uppercase;color:var(--dim)}
.ovaweb p{margin:3px 0 4px;font-size:13px;line-height:1.5;color:var(--ink)}
.ovasrc{display:flex;flex-wrap:wrap;gap:4px 10px}
.ovasrc a{font-size:12px;color:var(--acc);word-break:normal;text-decoration:none}
.ovasrc a:hover{text-decoration:underline}
.ovafrom{font-size:12.5px;color:var(--mid);font-style:italic;quotes:'“' '”'}
.ovawho{font-size:11.5px;color:var(--dim);margin-top:-4px}

/* ── made in the call: Ova's document card, and the document ─────────────── */
.cm.ova.made .madekind{font-size:10.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--acc);
  border:1px solid color-mix(in srgb,var(--acc) 40%,transparent);border-radius:999px;padding:2px 8px}
.cm.ova.made .madetitle{display:block;font-size:14px;color:var(--ink);margin:6px 0 2px;line-height:1.35}
.cm.ova.made .madewhy{display:block;font-size:11.5px;color:var(--dim);line-height:1.4}
.cm.ova.made .madeacts{display:flex;gap:6px;flex-wrap:wrap;margin-top:8px}
.cm.ova.made .madeacts button{all:unset;cursor:pointer;font-size:12.5px;padding:6px 11px;border-radius:9px;border:1px solid var(--line);color:var(--ink);background:var(--panel)}
.cm.ova.made .madeacts button.go{background:linear-gradient(90deg,#0794FC,#5B2EF2);color:#fff;border-color:transparent;font-weight:600}
.cm.ova.made .madeacts button:hover{border-color:var(--acc)}
.ghrow{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;margin-top:8px;padding-top:8px;border-top:1px dashed var(--line)}
.ghrow input[type=text]{flex:1 1 140px;min-width:0;font:inherit;font-size:12.5px;font-family:var(--mono,ui-monospace,monospace);color:var(--ink);
  background:var(--sunk,rgba(255,255,255,.04));border:1px solid var(--line);border-radius:8px;padding:6px 9px;outline:none}
.ghrow input[type=text]:focus{border-color:var(--acc)}
.ghclaude{font-size:12px;color:var(--mid);display:inline-flex;align-items:center;gap:5px;cursor:pointer;white-space:nowrap}
.ghgo{font-size:12.5px;font-weight:600;padding:6px 11px;border-radius:9px;background:var(--ink);color:var(--bg);text-decoration:none;cursor:pointer;white-space:nowrap}
.ghgo.off{opacity:.5}
.madeview{position:fixed;inset:0;z-index:80;background:rgba(5,7,10,.62);display:grid;place-items:center;padding:16px}
.madeview[hidden]{display:none}
.mv-sheet{width:min(720px,100%);max-height:min(86vh,900px);overflow:auto;background:var(--panel);border:1px solid var(--line);border-radius:18px;
  padding:20px 22px 24px;box-shadow:0 30px 90px rgba(0,0,0,.5);color:var(--ink)}
.mv-top{display:flex;align-items:center;justify-content:space-between;gap:10px}
.mv-top .madekind{font-size:10.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--acc)}
.mv-x{all:unset;cursor:pointer;font-size:22px;line-height:1;color:var(--mid);padding:2px 6px}
.mv-sheet h2{font-family:var(--display);font-size:22px;margin:8px 0 12px;line-height:1.25}
.mv-sheet h3{font-size:14px;letter-spacing:.02em;margin:16px 0 6px;color:var(--ink)}
.mv-sheet p,.mv-sheet li{font-size:14px;line-height:1.55;color:var(--ink);margin:0 0 8px}
.mv-sheet ul{margin:0 0 8px;padding-left:20px}
.mv-q{display:block;font-size:12px;color:var(--dim);font-style:italic;margin-top:2px;quotes:'“' '”'}

/* ───────── drag to resize ─────────
   [stated, 2026-10-24] "ALLOW PEOPLE TO RESIZE THE VIEW WINDOWS THEMSELVES OF WHATEVER IS
   BEING SHOWN, EASY RESIZING IS GREAT." The line between two things sharing the stage
   (app.js placeGutters): a little handle you can see, which lights up under the pointer
   and while dragged. Placed over the gap between them, so it covers nothing. */
.gutter{position:absolute;z-index:7;display:flex;align-items:center;justify-content:center;touch-action:none;outline:none}
.gutter[hidden]{display:none}
.gutter.gx{width:12px;cursor:col-resize}
.gutter.gy{height:12px;cursor:row-resize}
.gutter::before{content:"";border-radius:4px;background:var(--mid);opacity:.38;transition:opacity .15s,background .15s,transform .15s}
.gutter.gx::before{width:4px;height:48px;max-height:50%}
.gutter.gy::before{height:4px;width:48px;max-width:50%}
.gutter:hover::before,.gutter:focus-visible::before,.gutter.drag::before{background:var(--blue);opacity:1}
.gutter.gx:hover::before,.gutter.gx.drag::before{transform:scaleY(1.5)}
.gutter.gy:hover::before,.gutter.gy.drag::before{transform:scaleX(1.5)}
.gutter:focus-visible{box-shadow:0 0 0 2px var(--blue);border-radius:6px}
body.resizing{user-select:none;-webkit-user-select:none}
body.resizing.rx,body.resizing.rx *{cursor:col-resize!important}
body.resizing.ry,body.resizing.ry *{cursor:row-resize!important}
/* while the line moves nothing under the pointer may take it — a video, the picture */
body.resizing #stage video,body.resizing #stage img{pointer-events:none}
/* Two screens side by side: each presenter's face is sized to their own screen, not to the
   window — a 150px circle on a screen dragged down to a third of the stage covered half of it.
   The size is set from the screen's width by app.js (sizeScreenFaces): a container query
   here (container-type on .scr) made Chrome drop the shared screen's <video> from layout
   when a picture went up beside it — a black screen until something restyled it. */
.spotlight.two .scr .spotface video{width:var(--facew,clamp(96px,11vw,164px))}
/* The row of faces at the height it was dragged to: the strip's box follows the
   variable the faces are sized by. Only ever on a computer (applySplits). */
#app.stripsized #grid{height:calc(var(--striph) + 14px)}

/* ── devices: which microphone, camera and speaker ─────────────────────────
   A chevron against the button it belongs to — where Meet and Zoom put it — opening a
   small menu above the bar. Narrow and a little shorter than the round controls, and
   pulled in towards its button, so it reads as part of the mic (or the camera) rather
   than as one more control in the row. */
/* align-self: a 34px button in a row of 44px ones sat at the top of the row — [stated,
   2026-10-30, feedback] "the upward dropdown chevrons … sit too high relative to their
   corresponding icons. Please vertically centre both chevrons". */
.ctl.devchev{width:20px;height:34px;border-radius:10px;margin-left:-5px;padding:0;color:var(--mid);
  align-self:center;display:grid;place-items:center}
.ctl.devchev svg{width:12px;height:12px;display:block;fill:none;stroke:currentColor;stroke-width:1.9;
  stroke-linecap:round;stroke-linejoin:round}
.ctl.devchev:hover{color:var(--ink)}
.ctl.devchev[aria-expanded="true"]{background:var(--onbg);border-color:var(--online);color:var(--acc)}
/* Its own hover label would sit on top of the menu it just opened. */
.ctl.devchev[aria-expanded="true"]::after,.ctl.devchev[aria-expanded="true"]::before{display:none}
/* No room for two more controls in a phone's single row (see the 400px block above);
   a phone chooses its devices in Settings, and flips its camera with the flip button. */
@media (max-width:900px){ .ctl.devchev{display:none} }

.devmenu{position:absolute;bottom:calc(100% + 10px);left:0;z-index:25;width:min(320px,calc(100vw - 16px));
  padding:12px 14px;background:var(--panel2);border:1px solid var(--line);border-radius:14px;box-shadow:var(--shadow)}
.devmenu[hidden]{display:none}
/* The microphone's chevron is about sound: the microphone and the speaker. The camera's
   is about the picture. One menu, two views of it. */
.devmenu[data-for="mic"] .devrow[data-devrow="videoinput"],
.devmenu[data-for="cam"] .devrow:not([data-devrow="videoinput"]){display:none}
.devrow{display:block;margin:0 0 12px}
/* Filter out background noise (app.js filterTrack), under the microphone's list. */
.devrow.devns{display:flex;align-items:center;gap:8px;margin-top:-4px;font-size:13px;color:var(--ink);cursor:pointer}
.devrow.devns input{width:16px;height:16px;margin:0;flex:none;accent-color:var(--blue);cursor:pointer}
.devrow:last-child{margin-bottom:0}
.devrow[hidden]{display:none}
.devname{display:block;font-size:11px;letter-spacing:.07em;text-transform:uppercase;color:var(--dim);margin:0 0 5px}
.devrow select.f{margin-top:0;padding:8px 10px;font-size:13px;cursor:pointer}
.devrow select.f:disabled{cursor:default;color:var(--dim)}
.devfields .devrow:last-of-type{margin-bottom:0}
.devlevel{display:block;height:4px;margin-top:7px;border-radius:2px;background:var(--sunk);overflow:hidden}
.devlevel b{display:block;height:100%;width:0;border-radius:2px;background:var(--good);transition:width .1s linear}
.sheet-body .devfields{margin-top:4px}

/* ── the host's menu for one person ───────────────────────────────────────── */
.tileact[hidden]{display:none}
.tileact.host{font-size:16px;letter-spacing:-.04em}
.hostmenu{position:fixed;z-index:85;min-width:210px;max-width:min(300px,calc(100vw - 16px));padding:6px;
  background:var(--panel2);border:1px solid var(--line);border-radius:12px;box-shadow:var(--shadow);color:var(--ink)}
.hostmenu[hidden]{display:none}
.hostmenu .hmhead{margin:5px 9px 6px;font-size:12.5px;font-weight:600;color:var(--ink);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hostmenu.confirm .hmhead{white-space:normal;font-size:13.5px;line-height:1.35}
.hostmenu .hmnote{margin:0 9px 11px;font-size:12.5px;line-height:1.45;color:var(--mid)}
.hostmenu > button{display:block;width:100%;text-align:left;padding:8px 10px;border-radius:8px;font-size:13px;color:var(--ink)}
.hostmenu > button:hover:not(:disabled),.hostmenu > button:focus-visible{background:var(--hover);outline:none}
.hostmenu > button:disabled{color:var(--dim);cursor:default}
.hostmenu .hmdanger{color:var(--bad)}
.hmrow{display:flex;gap:8px;justify-content:flex-end;padding:0 4px 4px}
.hmrow button{padding:7px 13px;border-radius:9px;font-size:12.5px;border:1px solid var(--line);background:var(--field);color:var(--ink)}
.hmrow button:hover{background:var(--hover)}
.hmrow .hmgo{background:var(--offbg);border-color:var(--offline);color:var(--offink);font-weight:600}
.hmrow .hmgo:hover{background:var(--offbg);border-color:var(--offink)}
.person .hostact{font-size:13px;min-width:30px}
.person.hostrow{padding-top:2px}
.person.hostrow .who2{color:var(--mid);font-size:12.5px}
.person .hostact:disabled{opacity:.5;cursor:default}
.knock .note{font-size:11.5px;color:var(--dim);white-space:nowrap}

/* ── removed by the host ──────────────────────────────────────────────────── */
.removedcard{text-align:center}
.removedcard h2{margin-bottom:10px}
.removedacts{display:flex;gap:10px;justify-content:center;flex-wrap:wrap;margin-top:18px}
.removedacts .btn{text-decoration:none;display:inline-flex;align-items:center}

/* ── a phone's one row: nothing cut off, Leave always in reach ─────────────
   The row is a sideways scroller centred with justify-content:center — and a centred
   flex row that is too wide overflows BOTH ends, where the left end cannot be scrolled
   to. On a 390px phone that was the microphone, cut in half and unreachable. Auto
   margins centre the row while it fits and fall to zero when it does not, so any
   overflow is at the end the scroller reaches. Leave rides the row's right edge
   (sticky inside the scroller) so it is never the button you have to scroll to find. */
@media (max-width:900px){
  .bar-mid{justify-content:flex-start}
  .bar-mid > :first-child{margin-left:auto}
  .bar-mid > .ctl.leave{position:sticky;right:0;z-index:1;margin-right:auto;
    box-shadow:-10px 0 10px -6px var(--panel)}
}
/* Every control in one row on a phone. Measured with two cameras (every phone has a
   front and a back, so the flip button is there) and no screen sharing: from 430px down
   to 360px everything fits with a hang-up icon in place of the word and the buttons a
   step smaller each time; at 360 Captions goes back into Settings, where it also lives.
   Below that the row scrolls, Leave staying put at its end. */
.ctl.leave .leaveic{display:none}
@media (max-width:480px){
  .ctl,.ctl.wide-ctl{width:35px;height:35px}
  .ctl.leave{width:35px;height:35px;padding:0;justify-content:center}
  .ctl.leave .leavetx{display:none}
  .ctl.leave .leaveic{display:block;width:22px;height:22px;fill:currentColor;stroke:none}
}
@media (max-width:420px){
  .ctl,.ctl.wide-ctl,.ctl.leave{width:34px;height:34px}
  .bar-mid{gap:2px}
}
@media (max-width:400px){
  .ctl,.ctl.wide-ctl,.ctl.leave{width:33px;height:33px}
  .bar-mid{gap:1px}
}
@media (max-width:380px){
  .ctl,.ctl.wide-ctl,.ctl.leave{width:31px;height:31px}
}
@media (max-width:370px){
  #capBtn{display:none}
}

/* ── over a shared screen, in the light theme ─────────────────────────────
   The bar and the face over a screen sit on the screen's own black, in both themes, so
   their text is light in both. "Stop presenting" was a theme button — white on the
   light theme's white — and the name under the presenter's face was the light theme's
   ink on the screen's black: both unreadable, seen on staging with two screens up. And
   the meeting's red REC pill sat exactly under the presenter's bar on a computer, so it
   moves below it whenever a screen is up (a phone already did that, at 52px). */
.spotbar .btn{background:rgba(255,255,255,.12);border:1px solid rgba(255,255,255,.24);color:#F4F7FF}
.spotbar .btn:hover{background:rgba(255,255,255,.22);border-color:rgba(255,255,255,.4)}
.spotface span{color:#F4F7FF}
#app.presenting:not(.facstage) .recdots{top:66px}
@media (max-width:900px){ #app.presenting:not(.facstage) .recdots{top:52px} }


/* ───────── the layout menu ─────────
   [stated, 2026-10-30] "IT SHOULD BE ONE OPTION WHERE YOU SEE EVERYONE WHO IS ON VIDEO IN THE
   MAIN AREA THATS SORTED". The layout button opens three choices instead of flipping
   between two: Everyone, Cameras on, Speaker. It sits over the button like the device menu. */
.viewmenu{width:min(300px,calc(100vw - 16px));padding:6px}
.viewmenu .vmopt{all:unset;box-sizing:border-box;display:flex;align-items:center;gap:12px;width:100%;
  padding:9px 10px;border-radius:10px;cursor:pointer;color:var(--ink)}
.viewmenu .vmopt:hover,.viewmenu .vmopt:focus-visible{background:var(--sunk)}
.viewmenu .vmopt:focus-visible{outline:2px solid var(--acc2);outline-offset:-2px}
.viewmenu .vmopt svg{flex:none;width:22px;height:22px;fill:none;stroke:currentColor;stroke-width:1.6}
.viewmenu .vmopt span{display:flex;flex-direction:column;gap:2px;min-width:0}
.viewmenu .vmopt b{font-size:13.5px;font-weight:600}
.viewmenu .vmopt small{font-size:11.5px;color:var(--dim);line-height:1.35}
.viewmenu .vmopt[aria-checked="true"]{background:color-mix(in srgb,var(--acc2) 16%,transparent)}
.viewmenu .vmopt[aria-checked="true"] b::after{content:' ✓';color:var(--acc2)}
#viewBtn[aria-expanded="true"]{border-color:var(--acc2)}

/* ───────── nothing over the first row of faces ─────────
   The REC chip and the theme switch used to float over the top corners of the stage,
   which in a full grid is the first tile's corner — measured on Jack's call: REC on
   Viaksh's face. On a computer they get a band of their own above the faces. */
@media (min-width:901px){
  #stage:has(> .recdots > .recdot:not([hidden])){padding-top:54px}
  .recdots{top:14px;left:14px;flex-direction:row}
}

/* ───────── pictures: the Board's cards work like the column's ─────────
   [stated, 2026-10-30] "I LIKE THE SPLIT VERSION HALF HALF IT SHOULD BE THAT WAY INSIDE THE
   BRAINSTORM TAB AS WELL". A Board card is the column's card: the picture split down the
   middle, Me only on the left half and Show everyone on the right, instead of two small
   buttons wrapping over the top of it. */
.shot .shotacts{position:absolute;left:0;right:0;top:0;aspect-ratio:16/9;z-index:2;display:grid;
  grid-template-columns:1fr 1fr;gap:0;opacity:0;transition:opacity .15s ease}
.shot .shotacts .btn{all:unset;box-sizing:border-box;cursor:pointer;display:grid;place-items:center;text-align:center;
  padding:0 8px;font-size:12.5px;font-weight:600;line-height:1.25;color:#fff;background:rgba(8,11,16,.6)}
.shot .shotacts .meonly{border-right:1px solid rgba(255,255,255,.2)}
.shot .shotacts .meonly:hover,.shot .shotacts .meonly:focus-visible{background:rgba(7,148,252,.78)}
.shot .shotacts .showall:hover,.shot .shotacts .showall:focus-visible{background:rgba(91,46,242,.85)}
.shot:hover .shotacts,.shot .shotacts:focus-within{opacity:1}
@media (hover:none){ .shot .shotacts{opacity:.95} }

/* × on a card in the column: out of the column for you, still on the Board. */
.ps-x{all:unset;box-sizing:border-box;position:absolute;top:5px;right:5px;z-index:3;width:22px;height:22px;
  display:grid;place-items:center;border-radius:50%;cursor:pointer;font-size:15px;line-height:1;color:#fff;
  background:rgba(8,11,16,.78);border:1px solid rgba(255,255,255,.22);opacity:0;transition:opacity .15s ease}
.ps-card:hover .ps-x,.ps-x:focus-visible{opacity:1}
.ps-x:hover{background:rgba(229,72,77,.9);border-color:transparent}
@media (hover:none){ .ps-x{opacity:.95} }
/* × on the picture itself: always there, because the bar under it tucks itself away. */
.imgspot .isp-x{all:unset;box-sizing:border-box;position:absolute;top:10px;right:10px;z-index:4;width:30px;height:30px;
  display:grid;place-items:center;border-radius:50%;cursor:pointer;font-size:19px;line-height:1;color:#fff;
  background:rgba(8,11,16,.72);border:1px solid rgba(255,255,255,.24);backdrop-filter:blur(6px)}
.imgspot .isp-x:hover,.imgspot .isp-x:focus-visible{background:rgba(8,11,16,.92);border-color:rgba(255,255,255,.5)}
#app.pinover .imgspot .isp-x{display:none}

/* ───────── "your network is blocking this call" ─────────
   Said to the person whose own network has no way out (app.js netProbe), across the top
   of the stage, until it is fixed or hidden. Amber, like every other "something is wrong". */
.netwarn{position:absolute;left:50%;top:10px;transform:translateX(-50%);z-index:30;display:flex;align-items:center;gap:12px;
  width:min(640px,calc(100% - 24px));box-sizing:border-box;padding:10px 12px 10px 16px;border-radius:12px;
  background:rgba(40,24,4,.94);border:1px solid rgba(255,176,32,.55);color:#FFE2B8;font-size:13px;line-height:1.4;
  box-shadow:0 12px 34px rgba(0,0,0,.45)}
.netwarn .nw-words{flex:1;min-width:0}
.netwarn b{color:#fff}
.netwarn .btn{flex:none;font-size:12.5px;padding:6px 12px}
.netwarn .nw-x,.updnote .nw-x{all:unset;cursor:pointer;flex:none;width:24px;height:24px;display:grid;place-items:center;border-radius:50%;font-size:16px;color:#FFE2B8}
.netwarn .nw-x:hover,.updnote .nw-x:hover{background:rgba(255,255,255,.12)}

/* "TeamMeet was just updated" — after a reconnect to a newer build (app.js offerUpdate). */
.updnote{position:absolute;left:50%;bottom:14px;transform:translateX(-50%);z-index:30;display:flex;align-items:center;gap:12px;
  width:max-content;max-width:calc(100% - 24px);box-sizing:border-box;padding:9px 10px 9px 16px;border-radius:12px;
  background:var(--panel2);border:1px solid var(--acc2);color:var(--ink);font-size:13px;line-height:1.4;box-shadow:var(--shadow)}
.updnote .btn{flex:none;font-size:12.5px;padding:6px 12px}
.updnote .nw-x{color:var(--mid)}


/* ───────── who is speaking, at a glance ─────────
   A level in the name chip that moves with their voice, and their initial pulsing with it
   (app.js paintSpeaking sets --lvl, 0–1). [stated, 2026-10-30, feedback] "no audio waveform
   to identify which person is speaking". */
.tile .chip .wave{display:none;align-items:flex-end;gap:2px;height:11px;flex:none}
.tile.speaking .chip .wave{display:inline-flex}
.tile .chip .wave i{width:3px;border-radius:2px;background:#2BD9A6;height:calc(3px + var(--lvl,0) * 6px);
  transition:height .12s ease;animation:tmwave .55s ease-in-out infinite alternate}
.tile .chip .wave i:nth-child(2){height:calc(4px + var(--lvl,0) * 7px);animation-delay:-.2s}
.tile .chip .wave i:nth-child(3){height:calc(3px + var(--lvl,0) * 5px);animation-delay:-.4s}
@keyframes tmwave{from{transform:scaleY(.6)}to{transform:scaleY(1)}}
.tile .chip .wave i{transform-origin:bottom}
.tile.speaking .avatar{box-shadow:0 0 0 2px rgba(43,217,166,.95),0 0 0 calc(3px + var(--lvl,0) * 9px) rgba(43,217,166,.22)}
@media (prefers-reduced-motion:reduce){ .tile .chip .wave i{animation:none} }

/* ───────── muted for you ─────────
   Only you turned their sound off — said on their tile with the way back, in its own look:
   not their own mute (the mic mark), not a connection problem (amber). */
.tile .mutedforyou{all:unset;box-sizing:border-box;position:absolute;left:50%;top:8px;transform:translateX(-50%);z-index:5;
  display:inline-flex;align-items:center;gap:6px;max-width:calc(100% - 16px);padding:4px 6px 4px 9px;border-radius:999px;
  background:rgba(8,11,24,.86);border:1px solid rgba(159,176,216,.45);color:#E4E9F7;font-size:11.5px;cursor:pointer;white-space:nowrap}
.tile .mutedforyou svg{width:13px;height:13px;flex:none;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.tile .mutedforyou span{overflow:hidden;text-overflow:ellipsis}
.tile .mutedforyou b{font-weight:600;padding:2px 8px;border-radius:999px;background:#E4E9F7;color:#0b1020}
.tile .mutedforyou:hover b,.tile .mutedforyou:focus-visible b{background:#fff}
.tile.compactchip .mutedforyou span,.tile.short .mutedforyou span{display:none}
.tile.compactchip .mutedforyou,.tile.short .mutedforyou{top:5px;padding:3px 5px 3px 7px;font-size:10.5px}
.tile.mutedforme .chip .nm::after{content:none}

/* The presenter, while their face is in the circle over their screen, is not also a
   thumbnail in the strip (app.js renderGrid, `faced`). */
#stagearea .tile.faced{display:none}

/* The pictures' column moves: a handle at its head, a hand while it is held. */
.ps-head{display:flex;gap:6px;align-items:center;justify-content:flex-end}
.ps-grip{all:unset;box-sizing:border-box;cursor:grab;width:26px;height:24px;display:grid;place-items:center;border-radius:999px;
  background:rgba(8,11,16,.72);border:1px solid rgba(255,255,255,.16);backdrop-filter:blur(6px);color:#e9edff;touch-action:none}
.ps-grip svg{width:12px;height:12px;fill:currentColor}
.ps-grip:hover,.ps-grip:focus-visible{border-color:rgba(255,255,255,.4)}
.picstack.dragging .ps-grip{cursor:grabbing}
.picstack.dragging{transition:none}
.picstack.moved{align-items:flex-start}
/* …and on each card, the same grip while the pointer is on it: the card itself can be
   dragged (app.js wireDeckDrag). */
.ps-deck{touch-action:none}
.ps-move{position:absolute;left:50%;bottom:6px;transform:translateX(-50%);z-index:2;display:inline-flex;align-items:center;gap:5px;
  padding:3px 8px;border-radius:999px;font-size:10.5px;font-weight:600;letter-spacing:.02em;color:#e9edff;
  background:rgba(8,11,16,.78);border:1px solid rgba(255,255,255,.18);pointer-events:none;opacity:0;transition:opacity .15s ease;white-space:nowrap}
.ps-move svg{width:10px;height:10px;fill:currentColor}
.ps-card:hover .ps-move{opacity:1}
.picstack.dragging .ps-move{opacity:1}
.picstack.dragging .ps-deck,.picstack.dragging .ps-acts button{cursor:grabbing}
@media (hover:none){ .ps-move{display:none} }
.fbnews{margin:14px 0 0;font-size:13px}

/* Reactions on transcript lines. The add button only shows on the line under the mouse
   (always on a touch screen); reactions that exist always show. */
.txline .txreact{display:inline-flex;flex-wrap:wrap;gap:4px;margin-left:6px;vertical-align:middle}
.txline .txr{all:unset;box-sizing:border-box;cursor:pointer;font-size:12px;line-height:1;padding:3px 7px;border-radius:999px;
  border:1px solid var(--line);background:var(--sunk);color:var(--ink)}
.txline .txr.mine{border-color:var(--acc2);background:color-mix(in srgb,var(--acc2) 18%,transparent)}
.txline .txr:hover,.txline .txr:focus-visible{border-color:var(--acc2)}
.txline .txr.add{opacity:0;color:var(--mid)}
.txline:hover .txr.add,.txline .txr.add:focus-visible,.txline .txreact:focus-within .txr.add{opacity:1}
@media (hover:none){ .txline .txr.add{opacity:.7} }
.txline .txpick{display:inline-flex;gap:3px}

/* ── the live story (Tellavision): a pane on the stage like the picture's ─────────────────
   [stated, 2026-10-31] "…turns into its own video, shared video class like the pop-up image".
   Tellavision's own page fills it (public/tv/, its controls over its picture); this bar —
   Turn off for everyone, Full screen, Close for me — sits at the top left, where the page's
   own controls are not (its pens are top right, its themes and scenes along the foot). */
.tvspot .tv-frame{position:relative;flex:1 1 auto;align-self:stretch;min-height:0;display:flex;border-radius:14px;overflow:hidden;
  border:1px solid rgba(255,255,255,.14);box-shadow:0 24px 80px rgba(0,0,0,.6);background:#05050a}
.tvspot iframe{flex:1 1 auto;display:block;width:100%;height:100%;border:0;background:#05050a}
/* not on show here (closed for me, or a picture is up): off the screen, still its size, still drawing */
.tvspot.tv-away{position:fixed!important;left:-12000px;top:0;width:960px;height:600px;visibility:hidden;pointer-events:none}
/* [stated, 2026-11-01] "TELL A VISION SHOULD … USE THE ENTIRE AVAIL SPACE". On show, the frame is
   the picture's own shape, as big as the room allows, in pixels from fitTv (app.js) — never a box
   of some other shape with the picture letterboxed inside it. Every layout, an upright phone's too. */
.tvspot:not(.tv-away) .tv-frame{flex:none;align-self:center}
/* A touch screen with room beside the picture (a phone held sideways): the bar is a column beside
   it rather than a row under it, so the picture keeps the stage's whole height. 176px is fitTv's
   TV_SIDE_W. */
.tvspot.tv-side{flex-direction:row;column-gap:10px}
.tvspot.tv-side .tv-bar{flex:0 0 176px;width:176px;flex-direction:column;align-items:stretch;flex-wrap:nowrap;gap:6px}
.tvspot.tv-side .tv-bar .isp-cap{flex:none;white-space:normal;text-align:left;max-width:none}
.tvspot.tv-side .tvwordsw{flex-wrap:wrap;justify-content:space-between;border-radius:12px}
.tvspot.tv-side .tvwordsw b{flex:1 0 100%;padding:3px 8px 2px}
@media (hover:hover) and (pointer:fine){
  /* placed by fitTv on the picture's corner; from the left, so a row too wide for it is never
     cut at both ends — and if even a row of its own is too narrow, the caption goes on top */
  .tvspot .isp-bar.tv-bar{top:12px;bottom:auto;left:12px;transform:none;max-width:calc(100% - 24px);justify-content:flex-start}
  .tvspot .isp-bar.tv-bar.tv-wrap{flex-wrap:wrap;row-gap:6px}
  .tvspot .isp-bar.tv-bar.tv-wrap .isp-cap{flex:1 0 100%;max-width:none;text-align:left}
}
/* Words (Off, Simple, Emotive) — [stated, 2026-11-01] "OPTION FOR THE CAPTIONS PART ISNT THERE LIKE
   THE LIVE TEXT". Three buttons in one pill, the chosen one filled; the bar is on the page under the
   picture on a touch screen (theme colours) and over the picture where there is a mouse (light on
   dark, like the buttons beside it). */
.tvwordsw{display:inline-flex;align-items:center;gap:2px;flex:0 0 auto;padding:2px;border:1px solid var(--line);border-radius:999px}
.tvwordsw b{font-size:12px;font-weight:600;color:var(--mid);padding:0 5px 0 8px}
.tvwordsw button{all:unset;box-sizing:border-box;cursor:pointer;font-size:12.5px;line-height:1.2;padding:4px 9px;border-radius:999px;color:var(--ink);white-space:nowrap;text-align:center}
.tvwordsw button:hover{background:var(--panel2)}
.tvwordsw button[aria-checked="true"]{background:var(--ink);color:var(--bg)}
.tvwordsw button:focus-visible{outline:2px solid var(--blue);outline-offset:1px}
@media (hover:hover) and (pointer:fine){
  .tvspot .isp-bar .tvwordsw{border-color:rgba(255,255,255,.28)}
  .tvspot .isp-bar .tvwordsw b{color:#aab4d4}
  .tvspot .isp-bar .tvwordsw button{color:#e9edff}
  .tvspot .isp-bar .tvwordsw button:hover{background:rgba(255,255,255,.12)}
  .tvspot .isp-bar .tvwordsw button[aria-checked="true"]{background:#e9edff;color:#0b0e16}
}
.tvspot:fullscreen .tvwordsw{border-color:rgba(255,255,255,.25)}
.tvspot:fullscreen .tvwordsw b{color:#aab4d4}
.tvspot:fullscreen .tvwordsw button{color:#e9edff}
.tvspot:fullscreen .tvwordsw button[aria-checked="true"]{background:#e9edff;color:#0b0e16}
/* The words are on the story: the caption strip steps aside on this screen while it holds the stage. */
#app.tvstage.tvwords .captions{display:none}
.tvcard .tvrow{display:flex;gap:8px;align-items:center;margin:0 0 6px}
.tvswitch{display:inline-flex;align-items:center;gap:7px}
.tvswitch.on{border-color:var(--good);color:var(--ink)}
.tvswitch.on::before{content:'';width:7px;height:7px;border-radius:50%;background:var(--good);animation:ispLive 1.8s ease-out infinite}
@media (prefers-reduced-motion:reduce){.tvswitch.on::before{animation:none}}

