/* ==========================================================================
   GENERATED — do not edit. Run `node scripts/sync-editor-chrome.js`.

   The recorder's island, taken from `app/src/styles.css` by class name and
   scoped under `.rv-dock` so it cannot reach the rest of the site. The web
   recorder wears the app's bar because it is the same bar: the same pills, the
   same dividers, the same single mass of ink for Record.

   source: c926736ef4ac8ffd
   ========================================================================== */

.rv-dock .viewbtn{ line-height: 0; }
.rv-dock .viewbtn .vi{ display: none; }
:root[data-view="night"] .viewbtn .vi-sun, :root[data-theme="midnight"] .rv-dock .viewbtn .vi-sun, :root[data-view="daylight"] .viewbtn .vi-moon, :root:not([data-theme="midnight"]) .rv-dock .viewbtn .vi-moon{ display: block; }
.rv-dock .tray, .rv-dock .topbtn, .rv-dock .btn-primary, .rv-dock .btn-quiet, .rv-dock .pill-opt, .rv-dock .record-btn, .rv-dock .authchip, .rv-dock .plan-name, .rv-dock .rec-chip, .rv-dock .area-badge, .rv-dock .lib-card, .rv-dock .mirror-pill, .rv-dock .isl-pill, .rv-dock .isl-tog, .rv-dock .isl-split, .rv-dock .menu-trigger, .rv-dock .toggle, .rv-dock .fchip, .rv-dock .pick-card, .rv-dock .share-opt, .rv-dock .setup-row, .rv-dock .link-box, .rv-dock .custom-chip, .rv-dock .overlay-card, .rv-dock .tf, .rv-dock .roundbtn{
  position: relative;
}
.rv-dock :is(
  .pill-opt, .isl-pill, .isl-split, .topbtn, .authchip, .lib-card,
  .fchip, .pick-card, .share-opt, .setup-row, .toggle, .custom-chip,
  .plan-name, .roundbtn
)::before{
  content: "";
  position: absolute;
  inset: 0;
  border: 1.2px solid var(--pen-quiet);
  border-radius: inherit;
  filter: url(#rough-b);
  pointer-events: none;
}
body.rv-dock-body :is(
  .btn-primary, .btn-quiet, .record-btn, .menu-trigger,
  .link-box, .timeline, .mo-track
)::before{
  content: "";
  position: absolute;
  inset: 0;
  border: 1.3px solid var(--pen);
  border-radius: inherit;
  filter: url(#rough-a);
  pointer-events: none;
}
body.rv-dock-body :is(
  .stage, .tray, .overlay-card, .island, .menu-pop, .picker,
  .confirm-card, .fs-dock, .bg-frame
)::before{
  content: "";
  position: absolute;
  inset: 0;
  /* Thicker than the fine pens on purpose: the large filter displaces by 2.4px
     and a line thinner than its own displacement tears into dashes. This is
     the pair of numbers that decides whether the app looks drawn or looks like
     it has a rendering bug — they move together or not at all. */
  border: 2.1px solid var(--pen);
  border-radius: inherit;
  filter: url(#rough-lg);
  pointer-events: none;
}
.rv-dock .tf::after{
  content: "";
  position: absolute;
  inset: 0;
  border: 1.2px solid var(--pen-quiet);
  border-radius: var(--r-sm);
  filter: url(#rough-b);
  pointer-events: none;
}
.rv-dock .tf:focus-within::after{ border-color: var(--pen); }
.rv-dock :is(.pill-opt.active, .rec-chip)::before{ border-color: transparent; }
.rv-dock .pill-opt.active{
  background: var(--ink);
  color: var(--on-accent);
  border-color: transparent;
}
body.rv-dock-body :is(
  .stage, .island, .tray, .overlay-card, .isl-pill, .isl-tog, .topbtn,
  .btn-primary, .btn-quiet, .pill-opt, .authchip, .lib-card, .menu-pop,
  .menu-trigger, .fchip, .pick-card, .share-opt, .setup-row, .toggle,
  .link-box, .timeline
){
  border-color: transparent;
}
.rv-dock .viewbtn svg, .rv-dock .iconbtn svg, .rv-dock .roundbtn svg, .rv-dock .menu-chev{ filter: url(#rough-ink); }
.rv-dock :is(.tray-scroll, .panel-scroll, .picker-body, .fs-dock, .status, .ws-panel-scroll){
  scrollbar-gutter: stable;
}
.rv-dock :is(.tray-scroll, .panel-scroll, .picker-body, .fs-dock, .status, .ws-panel-scroll)::-webkit-scrollbar{
  width: 10px;
  height: 10px;
}
.rv-dock :is(.tray-scroll, .panel-scroll, .picker-body, .fs-dock, .status, .ws-panel-scroll)::-webkit-scrollbar-track{
  background: transparent;
}
.rv-dock :is(.tray-scroll, .panel-scroll, .picker-body, .fs-dock, .status, .ws-panel-scroll)::-webkit-scrollbar-thumb{
  background: color-mix(in srgb, var(--ink) 22%, transparent);
  border-radius: 999px;
  border: 3px solid transparent;
  background-clip: content-box;
}
.rv-dock :is(.tray-scroll, .panel-scroll, .picker-body, .fs-dock, .status, .ws-panel-scroll)::-webkit-scrollbar-thumb:hover{
  background-color: color-mix(in srgb, var(--ink) 38%, transparent);
}
.rv-dock :is(.tray-scroll, .panel-scroll, .picker-body, .fs-dock, .status, .ws-panel-scroll)::-webkit-scrollbar-corner{
  background: transparent;
}
body.rv-dock-body .hidden{ display: none !important; }
.rv-dock .native-hidden{ position: absolute; opacity: 0; pointer-events: none; width: 0; height: 0; }
.rv-dock .roundbtn{
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 50%;
  background: transparent;
  color: var(--mut);
  cursor: pointer;
  transition: color var(--fast), background var(--fast);
}
.rv-dock .roundbtn::before{ opacity: 0; transition: opacity var(--fast); }
.rv-dock .roundbtn:hover{ color: var(--ink); }
.rv-dock .roundbtn:hover::before{ opacity: 1; }
.rv-dock .roundbtn:disabled{ opacity: 0.35; pointer-events: none; }
.rv-dock .roundbtn.lead{
  width: 44px;
  height: 44px;
  background: var(--ink);
  color: var(--on-accent);
}
.rv-dock .roundbtn.lead::before{ opacity: 0; }
.rv-dock .roundbtn.lead:hover{ background: color-mix(in srgb, var(--ink) 88%, var(--paper)); }
.rv-dock .roundbtn.lead:active{ transform: scale(0.96); }
.rv-dock .roundbtn.edged::before{ opacity: 1; }
.rv-dock .roundbtn.mid{ width: 34px; height: 34px; }
.rv-dock .roundbtn.sm{ width: 26px; height: 26px; }
.rv-dock .authchip{
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  font-weight: 500;
  color: var(--mut);
  padding: 5px 11px 5px 9px;
  border-radius: 999px;
  background: var(--card);
}
.rv-dock .auth-dot{ width: 6px; height: 6px; border-radius: 50%; background: var(--faint); }
.rv-dock .auth-dot.ok{ background: var(--green); }
.rv-dock .auth-dot.bad{ background: var(--red); }
.rv-dock .controlbar{
  /* Pinned to the bottom of the column so its bottom edge is the column's
     bottom edge — the same line the drawer beside it ends on.

     It briefly took the leftover instead, so the dock sat in the middle of the
     band that opening a drawer left under the picture. Franz on that band:
     "trash". It is not there any more — a drawer widens the window rather than
     shrinking the picture, so there is no leftover to sit in. */
  flex: none;
  /* Under the picture, at a fixed distance — not pinned to the bottom of the
     column.
     `margin-top: auto` put the bar on the column's bottom edge and handed it
     whatever the aspect fit left over, so the air between the picture and
     Record was never the same twice: measured at three window sizes it came
     out 33, 18 and 18 while the air under Record stayed 14. Franz, 31 Aug:
     "this up and down padding from the record bar aint right man fix it
     permanently - has to be equal and uniform."
     6 here plus the 8 the dock is inset inside this band is 14, which is
     exactly the 8 + `.studio`'s own 6 below it. `margin-bottom: auto` sends the
     leftover to the floor of the column instead, where it is one gap at the
     very bottom rather than a number that moves under the thing you press. */
  margin-top: 6px;
  margin-bottom: auto;
  width: 100%;
  height: var(--bar-h, 56px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding-inline: 14px;
}
.rv-dock .dock{
  display: flex;
  align-items: center;
  gap: 2px;
  min-width: 0;
  max-width: 100%;
  padding: 4px 6px;
  border-radius: 999px;
  background: var(--card);
  position: relative;
}
.rv-dock .dock::before{
  content: "";
  position: absolute;
  inset: 0;
  border: 1.6px solid var(--pen-quiet);
  border-radius: inherit;
  filter: url(#rough-lg);
  pointer-events: none;
}
.rv-dock .dock-nav, .rv-dock .dock-utils{
  display: flex;
  align-items: center;
  gap: 2px;
  flex: none;
}
.rv-dock .dock-nav .isl-pill-plain{
  min-width: 0;
  padding: 5px 12px;
  font-size: clamp(9.5px, 1.28cqw, 12px);
  font-weight: 600;
  letter-spacing: -0.005em;
  color: var(--on-dark-mut);
}
.rv-dock .dock-utils{ margin-left: 2px; }
.rv-dock .dock-utils .roundbtn{ width: 32px; height: 32px; }
.rv-dock .dock > .isl-div{ margin: 0 6px; }
.rv-dock .controlbar .island{
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  /* Out of the stage: no longer absolutely placed, no longer glass, and as
     flat as the bar it sits in. It used to be a floating capsule that needed
     presence to read against footage; on paper, under the picture, presence is
     just noise — so it loses the fill and the pill and keeps only its outline.
     Slim: the controls are a line of text, not a toolbar. */
  position: static;
  transform: none;
  grid-column: 2;
  margin: 0;
  gap: 2px;
  padding: 0;
  height: 28px;
  max-width: none;
  background: transparent;
  backdrop-filter: none;
  animation: none;
}
.rv-dock .controlbar .island::before{ display: none; }
.rv-dock .controlbar .isl-pill, .rv-dock .controlbar .isl-tog, .rv-dock .controlbar .isl-pill-tail{
  padding-top: 4px;
  padding-bottom: 4px;
}
.rv-dock .controlbar .isl-pill{
  /* Shrinkable, so a long device name gives up width before the bar breaks —
     `.isl-name` already carries the ellipsis. Record and the separator stay
     `flex: none`: the thing you press must never move or change size.

     **With a floor.** Without one the chips shrank all the way to their dot:
     with a drawer open on a narrow window, Screen and Mic were two bare dots
     and only the camera still had a name. A recorder that cannot tell you what
     it is about to record is not one you would trust with a take. 88px is the
     dot, seven characters and the ellipsis — the point at which a label is
     still doing its job. */
  flex: 0 1 auto;
  min-width: 88px;
  gap: 7px;
  padding-inline: 12px;
  /* `justify-content: center` is what made the rhythm uneven — with an 88px box
     around every chip, "Screen" got 18px of air either side and "Mic" got 27,
     from one rule neither of them names. A chip is as wide as its own name
     plus 12 now, and only shrinks below that under real pressure.

     There used to be a `min-width: 0` here as well, undoing the 88px floor
     eleven lines above it in the same block — so the floor the comment
     defends did not exist. Measured with the Styles drawer open at 1080:
     "Main display" was rendering as **"M…"**, which is the dead control
     Franz banned ("this can never happen ever"). One of the two had to go and
     it was not the floor. */
  justify-content: flex-start;
}
.rv-dock .controlbar .dock-nav .isl-pill{ justify-content: center; }
.rv-dock .controlbar .isl-split{ flex: none; }
.rv-dock .controlbar .isl-tog{
  padding: 4px 0 4px 12px;
}
.rv-dock .controlbar .isl-pill-tail{
  min-width: 0;
  padding-left: 7px;
  padding-right: 12px;
}
.rv-dock .controlbar .record-btn{
  flex: none;
  gap: 8px;
  padding: 8px 22px;
  font-size: clamp(11.5px, 1.5cqw, 13.5px);
  letter-spacing: -0.005em;
  margin-inline: 2px;
}
.rv-dock .controlbar .record-btn .dot{
  position: relative;
  width: 9px;
  height: 9px;
}
.rv-dock .controlbar .record-btn .dot::after{
  content: "";
  position: absolute;
  inset: -4px;
  border-radius: 50%;
  border: 1.5px solid color-mix(in srgb, var(--red) 50%, transparent);
}
.rv-dock .controlbar .record-btn.recording .dot::after{ display: none; }
.rv-dock .controlbar .isl-div{ height: 14px; }
.rv-dock .controlbar .record-btn{ padding-top: 5px; padding-bottom: 5px; }
.rv-dock .pill-opt.pill-off{ opacity: 0.4; }
.rv-dock .field-note{
  display: block;
  margin-top: 6px;
  font-size: 11.5px;
  line-height: 1.35;
  color: var(--faint);
}
.rv-dock .field-note[hidden]{ display: none; }
.rv-dock .rec-chip{
  position: absolute;
  top: 14px;
  right: 16px;
  display: flex;
  align-items: center;
  gap: 8px;
  /* The chip sits on the dark mount in both themes, so it inverts against the
     picture rather than against the page: a bright mass with a red dot. Ink on
     ink would have made it disappear the moment the stage went dark. */
  background: var(--on-video);
  border: 1px solid transparent;
  color: #0a0f16;
  border-radius: 999px;
  padding: 6px 14px;
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.rv-dock .rec-dot{ width: 9px; height: 9px; border-radius: 50%; background: var(--red); animation: pulse 1.3s infinite; }
.rv-dock .isl-div{ width: 1px; height: 20px; background: var(--glass-line); flex: none; margin: 0 3px; }
.rv-dock .isl-pill{
  display: flex;
  align-items: center;
  gap: 7px;
  border: 1px solid transparent;
  background: none;
  color: var(--on-dark-mut);
  font-size: clamp(9.5px, 1.28cqw, 12px);
  font-weight: 600;
  letter-spacing: -0.005em;
  padding: clamp(5px, 0.75cqw, 7px) clamp(8px, 1.4cqw, 13px);
  border-radius: 999px;
  /* Elastic, not clamped. The pills used to be `flex: none; max-width: 168px`,
     which — on top of a hard character slice in renderIsland() — is how
     "MacBook Pro Camera" became "MacBook Pro…". They now take the width their
     name needs and only give it back under real pressure. The record button,
     the toggle and the separator stay `flex: none` so the thing you press
     never moves. */
  flex: 0 1 auto;
  min-width: clamp(58px, 9cqw, 88px);
  max-width: 240px;
  justify-content: center;
  white-space: nowrap;
  overflow: hidden;
  transition: color var(--fast);
}
.rv-dock .isl-pill > .pdot{ flex: none; }
.rv-dock .isl-name{
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rv-dock .isl-pill::before{ opacity: 0; transition: opacity var(--fast); }
.rv-dock .isl-pill:hover::before, .rv-dock .isl-pill.on::before, .rv-dock .isl-pill.open::before{ opacity: 1; }
.rv-dock .dock-nav .isl-pill::before{ opacity: 1; }
.rv-dock .isl-pill .pdot, .rv-dock .isl-tog .pdot{
  width: 7px; height: 7px; border-radius: 50%;
  background: none;
  box-shadow: inset 0 0 0 1.5px var(--mut);
  transition: background var(--fast), box-shadow var(--fast);
}
.rv-dock .isl-pill:hover{ color: var(--on-dark); }
.rv-dock .isl-pill.on{ color: var(--on-dark-mut); }
.rv-dock .isl-pill.on .pdot, .rv-dock .isl-split.on .isl-tog .pdot{ background: var(--ink); box-shadow: none; }
.rv-dock .isl-pill.open{ background: var(--hover); color: var(--on-dark); }
.rv-dock .isl-split{ position: relative; display: flex; align-items: stretch; flex: none; border-radius: 999px; }
.rv-dock .isl-split::before{ opacity: 0; transition: opacity var(--fast); }
.rv-dock .isl-split:hover::before, .rv-dock .isl-split.on::before{ opacity: 1; }
.rv-dock .isl-tog::before, .rv-dock .isl-pill-tail::before{ content: none; }
.rv-dock .isl-tog{
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
  padding: 0 clamp(8px, 1.3cqw, 12px) 0 clamp(9px, 1.5cqw, 14px);
  border: none;
  background: none;
  border-radius: 999px 0 0 999px;
  cursor: pointer;
  transition: all var(--fast);
}
.rv-dock .isl-tog:hover{ background: var(--hover); }
.rv-dock .isl-tog:disabled{ cursor: default; opacity: 0.45; }
.rv-dock .isl-tog:disabled:hover{ background: none; }
.rv-dock .isl-pill-tail{
  border-radius: 0 999px 999px 0;
  min-width: 86px;
  padding-left: 11px;
}
.rv-dock .isl-pill-plain{ min-width: 72px; padding: 7px 14px; }
body.rv-dock-body .menu-pop.fixed{ position: fixed; top: auto; min-width: 180px; }
.rv-dock .record-btn{
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--accent);
  color: var(--on-accent);
  border: none;
  border-radius: 999px;
  padding: clamp(6px, 1cqw, 9px) clamp(13px, 2.2cqw, 20px);
  font-size: clamp(10.5px, 1.4cqw, 13px);
  font-weight: 700;
  flex: none;
  margin-left: 3px;
  transition: transform var(--fast), background var(--fast), box-shadow var(--fast);
}
.rv-dock .record-btn:hover{ background: var(--accent-hi); transform: translateY(-1px); }
.rv-dock .record-btn:active{ transform: translateY(0); }
.rv-dock .record-btn:disabled{ opacity: 0.45; box-shadow: none; transform: none; }
.rv-dock .record-btn .dot{ width: clamp(7px, 1cqw, 9px); height: clamp(7px, 1cqw, 9px); border-radius: 50%; background: var(--red); flex: none; }
.rv-dock .record-btn::before{ opacity: 0; transition: opacity var(--fast); }
.rv-dock .record-btn.recording::before{ opacity: 1; }
.rv-dock .record-btn.recording{ background: var(--card); color: var(--ink); }
.rv-dock .record-btn.recording .dot{ background: var(--red); border-radius: 2px; animation: pulse 1.3s infinite; }
body.rv-dock-body .island .menu-trigger{
  background: var(--wash);
  border: 1px solid transparent;
  color: var(--on-dark-mut);
  border-radius: 999px;
}
body.rv-dock-body .island .menu-trigger:hover{
  background: var(--hover-strong);
  color: var(--on-dark);
}
body.rv-dock-body .island .menu-value{ max-width: 220px; }
body.rv-dock-body .menu{ position: relative; min-width: 0; }
body.rv-dock-body .menu-trigger{
  display: flex;
  align-items: center;
  gap: 7px;
  background: var(--card);
  border: 1px solid var(--line);
  color: var(--ink);
  border-radius: 999px;
  padding: 7px 12px;
  font-size: 12px;
  font-weight: 500;
  max-width: 100%;
  transition: border-color var(--fast), background var(--fast);
}
body.rv-dock-body .menu-trigger:hover{ border-color: var(--line-strong); }
body.rv-dock-body .menu-trigger:disabled{ opacity: 0.5; }
body.rv-dock-body .menu-value{
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 200px;
}
body.rv-dock-body .menu-chev{ font-size: 9px; opacity: 0.55; flex: none; }
body.rv-dock-body .menu-pop{
  position: absolute;
  left: 0;
  top: calc(100% + 6px);
  z-index: 200;
  min-width: 100%;
  max-width: 280px;
  background: var(--card);
  /* No shadow. CLAUDE.md §8: flat throughout, depth only on the app icon — and
     a drop-shadowed panel over a column of drawn boxes was the one thing in the
     window pretending to be above the page. The drawn edge does the lifting,
     the same one every box in the app wears. */
  border: 0;
  border-radius: var(--r-md);
  padding: 5px;
  display: flex;
  flex-direction: column;
  gap: 1px;
  animation: pop-in 0.16s var(--ease);
}
body.rv-dock-body .menu-pop::before{
  content: "";
  position: absolute;
  inset: 0;
  border: 1.3px solid var(--pen);
  border-radius: inherit;
  filter: url(#rough-a);
  pointer-events: none;
}
body.rv-dock-body .menu-pop.flip-right{ left: auto; right: 0; }
body.rv-dock-body .menu-pop.up{ top: auto; bottom: calc(100% + 6px); }
body.rv-dock-body .menu-item{
  border: none;
  background: none;
  text-align: left;
  color: var(--ink);
  font-size: 12.5px;
  font-weight: 500;
  padding: 8px 10px;
  border-radius: var(--r-sm);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: background var(--fast);
}
body.rv-dock-body .menu-item:hover{ background: var(--well); }
body.rv-dock-body .menu-item.rich{
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 9px 11px;
  white-space: normal;
}
body.rv-dock-body .menu-item.has-action{ position: relative; padding-right: 74px; }
body.rv-dock-body .menu-item.rich.on .mi-sub{ color: color-mix(in srgb, var(--red) 75%, transparent); }
body.rv-dock-body .menu-pop.fixed{ min-width: 230px; max-width: 300px; }
body.rv-dock-body .menu-item.on{ color: var(--accent); font-weight: 600; background: var(--accent-soft); }
.rv-dock .pillgroup{ display: flex; flex-wrap: wrap; gap: 6px; }
.rv-dock .pill-opt{
  display: inline-flex;
  align-items: center;
  gap: 7px;
  border: 1px solid transparent;
  /* No fill at rest. The pen is the shape; a card-coloured pill on a
     card-coloured tray was a rectangle you could only see because of its
     border, which is the thing we replaced. */
  background: none;
  color: var(--mut);
  font-size: 11.5px;
  font-weight: 600;
  padding: 7px 13px;
  /* **An integer height, so a grid of these has an integer rhythm.**
     Left to the font, the box came out 28.5px: the columns still sat exactly
     6px apart because they start from integer positions, but the rows landed on
     half pixels and the gaps rounded to 6.5, 5.5, 6.5. Three gaps, three
     different sizes, from one declared value. Pinning the line box makes every
     row identical, and it is set here rather than on `.pillgrid` so a flow pill
     and a grid pill stay the same height — they have been 30 against 28 before
     now, and it showed. */
  line-height: 14px;
  border-radius: 999px;
  white-space: nowrap;
  transition: background var(--fast), color var(--fast);
}
.rv-dock .pill-opt{ justify-content: center; }
.rv-dock .swatch-pills .pill-opt{ justify-content: flex-start; }
.rv-dock .pill-opt:hover{ background: var(--wash); color: var(--ink); }
.rv-dock .pill-opt.active{
  background: var(--ink);
  border-color: transparent;
  color: var(--paper);
}
.rv-dock .pill-opt.active:hover{ background: var(--ink); }
.rv-dock .pill-opt:disabled{ opacity: 0.4; }
.rv-dock .pill-opt:disabled:hover{ border-color: var(--line); color: var(--mut); }
.rv-dock .cam-bg-lens{ margin-bottom: 0; }
.rv-dock #cam-bg-pick > .seg{ margin-bottom: 10px; }
.rv-dock #cam-bg-pick .cam-bgpane > .ws-swatches:last-child, .rv-dock #cam-bg-pick .cam-bgpane > .chipgrid:last-child{ margin-bottom: 0; }
.rv-dock #cam-bg-pick .cam-bgpane{ margin-bottom: 0; }
.rv-dock .pillgrid{ display: grid; gap: 6px; }
.rv-dock .pillgrid-1{ grid-template-columns: minmax(0, 1fr); }
.rv-dock .pillgrid-2{ grid-template-columns: repeat(2, minmax(0, 1fr)); }
.rv-dock .pillgrid-3{ grid-template-columns: repeat(3, minmax(0, 1fr)); }
.rv-dock .pillgrid-4{ grid-template-columns: repeat(4, minmax(0, 1fr)); }
.rv-dock .pillgrid .pill-opt{
  width: 100%;
  min-width: 0;
  padding-inline: 8px;
  overflow: hidden;
  justify-content: center;
}
.rv-dock .pillgrid .pill-opt > .pill-lbl{
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rv-dock .chipgrid{
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 6px;
}
.rv-dock .chipgrid .pill-opt{
  width: 100%;
  min-width: 0;
  padding-inline: 10px;
}
.rv-dock .chipgrid .chip-name{ min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rv-dock .chipgrid .pill-opt.colour-chip{ padding: 7px 0; }
.rv-dock .colour-chip > .colour-chip-h{ display: block; height: 13px; }
.rv-dock .chipgrid .pill-opt.colour-chip.active{ outline: 2px solid var(--ink); outline-offset: 2px; }
.rv-dock .chipgrid .pill-opt.colour-chip-none{ background: var(--well); position: relative; }
.rv-dock .chipgrid .pill-opt.colour-chip-none::after{
  content: "";
  position: absolute;
  inset: 20%;
  border: var(--none-edge);
  border-radius: 4px;
}
.rv-dock .chipgrid .ws-sw-add{ grid-column: 1 / -1; }
.rv-dock .dotsw{
  width: 13px; height: 13px; border-radius: 50%;
  flex: none;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ink) 18%, transparent);
}
.rv-dock .swatch-pills .pill-opt.active .dotsw{ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--ink) 25%, transparent); }
.rv-dock .seg{
  display: flex;
  background: var(--well);
  border-radius: 9px;
  padding: 3px;
  gap: 2px;
  min-width: 0; /* segments were being clipped rather than sharing the room */
}
.rv-dock .seg-btn{
  flex: 1 1 0;
  min-width: 0;
  border: none;
  background: none;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--mut);
  padding: 6px 6px;
  overflow: hidden;
  text-overflow: ellipsis;
  border-radius: 7px;
  white-space: nowrap;
  transition: all var(--fast);
}
.rv-dock .seg-btn:hover{ color: var(--ink); }
.rv-dock .seg-btn.active{ background: var(--card); color: var(--ink); box-shadow: var(--shadow-sm); }
.rv-dock .stage-overlay{
  position: absolute;
  inset: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--veil-heavy);
  backdrop-filter: blur(4px);
}
.rv-dock .overlay-card{
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 11px;
  text-align: center;
  max-width: 420px;
  padding: 30px;
  /* The pen draws its outline with `border-radius: inherit`, and this card
     carried no radius at all — so the one moment the app asks you to wait was
     the one shape in it with square corners. It takes the same large radius the
     stage, the drawer and the dock take, and a card ground under it so it reads
     as a panel on the picture rather than as text with a box drawn round it. */
  border-radius: var(--r-lg);
  background: var(--card);
}
.rv-dock .overlay-ring{ width: 28px; height: 28px; border: 7px solid var(--accent); border-radius: 50%; }
.rv-dock .overlay-card h3{ color: var(--on-dark); font-size: 18px; font-weight: 700; letter-spacing: -0.02em; }
.rv-dock .overlay-card p{ color: var(--on-dark-mut); font-size: 13px; line-height: 1.55; }
.rv-dock .setup-card{ width: 440px; max-width: 92%; }
.rv-dock .setup-rows{ display: flex; flex-direction: column; gap: 7px; width: 100%; margin: 8px 0 2px; }
.rv-dock .setup-row{
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--wash);
  border: 1px solid var(--ctl-line);
  border-radius: 11px;
  padding: 11px 14px;
  transition: border-color var(--fast), background var(--fast);
}
.rv-dock .setup-row.ok{ background: rgba(63, 142, 90, 0.1); border-color: rgba(63, 142, 90, 0.3); }
.rv-dock .setup-name{ color: var(--on-dark); font-size: 13px; font-weight: 600; flex: 1; text-align: left; }
.rv-dock .setup-state{ font-size: 12px; font-weight: 700; }
.rv-dock .setup-row.ok .setup-state::after{ content: "✓"; color: var(--green); font-size: 15px; }
.rv-dock .setup-row.ok .setup-btn{ display: none; }
.rv-dock .setup-row.blocked .setup-state::after{ content: "blocked"; color: var(--red); font-size: 11px; }
.rv-dock .setup-row .setup-btn{
  padding: 6px 13px;
  font-size: 11.5px;
  background: var(--ctl-line);
  border-color: transparent;
  color: var(--on-dark);
}
.rv-dock .setup-row .setup-btn:hover{ background: var(--hover-strong); }
.rv-dock .set-action{
  width: 100%;
  justify-content: center;
  /* And one height. `.btn-primary` and `.btn-quiet` carry different padding —
     36px against 34 — which is invisible while they sit in different sections
     and would not be if they ever met. The drawer went to one pill height on
     30 Aug for the same reason; a button in it is not exempt. */
  min-height: 36px;
  padding-block: 0;
}
.rv-dock .tray-locked .ws-group-body{ opacity: 0.45; }
.rv-dock .tray-lock-note{ margin: 8px 0 0; }
.rv-dock .studio.drawer-over > .tray{
  position: absolute;
  top: 14px;
  right: 14px;
  /* Above the control bar, not down to the dock's own bottom edge the way the
     docked drawer sits. Docked they are side by side and can share that line;
     floating, a drawer that ran that far would be lying across the right end of
     the dock — Studio, the light and the gear, all under it and unreachable.
     The dock is the one control whose position the eye has learned. */
  bottom: calc(6px + var(--bar-h, 56px));
  margin-bottom: 0;
  z-index: 40;
  /* Opaque, because it is over the picture now rather than beside it. The
     84% card the docked drawer uses reads as a smudge on a moving preview. */
  background: var(--card);
}
.rv-dock .tray{
  flex: none;
  width: var(--drawer-w);
  align-self: stretch;
  /* The drawer ends on the dock's bottom edge, not on the band's.
     The band is 56px and the dock inside it is 40px, centred, so 8px of it is
     air — and a drawer that stretches the whole column ended 8px below the
     thing it is meant to line up with. The dock does not move: it is the one
     control whose position the eye has learned, and dropping it to the bottom
     of its band to fix a drawer was fixing the wrong element. */
  /* Measured, with the arithmetic as the fallback. `--tray-mb` is published by
     `trackDrawerFloor` in main.js and is the real distance from the column's
     floor to the dock's bottom edge; the calc behind it is what this rule used
     to be on its own, and is what a first paint gets before the measurement
     lands. See that function for why the arithmetic alone was never right. */
  margin-bottom: var(--tray-mb, calc((var(--bar-h, 56px) - var(--dock-h, 40px)) / 2));
  display: flex;
  flex-direction: column;
  /* The tray itself no longer scrolls — .tray-scroll inside it does.
     `position: absolute; inset: 0` inside a scroll container resolves against
     the *scrollable overflow area*, not the visible box, so the drawn outline
     was painted once at the scroll origin and slid away with the content: the
     border visibly stopped partway down the panel. The frame has to stay
     still, so the frame cannot be the thing that scrolls. */
  overflow: hidden;
  background: color-mix(in srgb, var(--card) 84%, transparent);
  backdrop-filter: blur(18px) saturate(1.1);
  border: 1px solid transparent;
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-lg);
  /* The entrance is a settle, not an arrival: the tray is already in layout
     and already the right size, so all that moves is its content, 14px in. */
  transition: opacity 0.26s var(--ease), transform 0.26s var(--ease);
}
.rv-dock .tray-scroll{
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  /* 14, the same as every other gap between two sections.
     The drawer's content is split across two `.tray-col`s, and this is the gap
     between them. It was 28 on the reasoning that a column boundary is a
     bigger break than a row — but the two columns never sit side by side.
     `.tray-scroll` is `flex-direction: column` at every width, and two 276px
     columns have never fitted in a 316px drawer, so they are simply the top
     and bottom halves of one list. That made the 28 a gap that appears once,
     between two boxes indistinguishable from every other pair, which is
     exactly what Franz saw on 30 Aug: a hole rather than a break. The section
     heads went 13/700 to 19/700 the same night and announce a section on their
     own now, so the extra air has nothing left to say. */
  gap: 14px;
  overflow-y: auto;
  /* Scroll containers need somewhere to end. 18px put the last control hard
     against the rounded bottom edge, so the final row read as clipped and
     there was nothing to tell you you had reached the end.
     44px was sized around a settings button that had been pasted into two of
     the three drawers by mistake; with those gone it was a hand's width of
     nothing after the last card, which reads as a list that failed to finish
     rather than one that ended. */
  overscroll-behavior: contain;
  /* The app's own 14px, on every side.
     Running the sections full-bleed put their drawn edge on top of the
     drawer's drawn edge — two wobbling ink lines a pixel apart down both
     sides, which is worse than either alone. A frame needs air inside it. */
  padding: 14px;
}
.rv-dock .tray{
  margin-right: calc(var(--drawer-w) * -1 - 14px);
  opacity: 0;
  transform: none;
  transition:
    margin-right 0.34s var(--ease),
    opacity 0.2s var(--ease);
  will-change: margin-right, opacity;
}
.rv-dock .tray.open{
  margin-right: 0;
  opacity: 1;
}
.rv-dock .tray:not(.open){ transition: margin-right 0.3s var(--ease), opacity 0.16s var(--ease); }
.rv-dock #tray .field:has(> #res-select) > .pillgroup .pill-opt[data-value="0"]{
  grid-column: span 2;
}
.rv-dock .tray-foot{
  flex: none;
  display: block;
  padding: 12px 16px 14px;
  position: relative;
}
.rv-dock .tray-foot::before{
  content: "";
  position: absolute;
  inset: 0;
  border-top: 1.3px solid var(--pen-quiet);
  filter: url(#rough-a);
  pointer-events: none;
}
.rv-dock .plan-line{
  margin: 0;
  min-width: 0;
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--mut);
}
.rv-dock .plan-card{ position: relative; }
.rv-dock .plan-top{
  display: flex;
  /* Centre, not baseline: one side is now a padded pill and the other is a
     line of text, and a shared baseline hangs the text off the badge's. */
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.rv-dock .plan-name{
  display: inline-flex;
  align-items: center;
  position: relative;
  font-family: var(--disp);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: -0.005em;
  color: var(--ink);
  line-height: 1;
  padding: 5px 11px 6px;
  border-radius: 999px;
  background: var(--card);
}
.rv-dock .plan-top-tier .plan-name::before{ border-color: var(--pen); }
.rv-dock .plan-state{
  font-size: 11px;
  font-weight: 600;
  color: var(--mut);
  letter-spacing: -0.005em;
}
.rv-dock .storage-read{
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.rv-dock .storage-bar{
  position: relative;
  height: 6px;
  margin-top: 8px;
  border-radius: 999px;
  background: var(--well);
  overflow: hidden;
}
.rv-dock .storage-bar i{
  display: block;
  height: 100%;
  width: 0;
  background: var(--ink);
  transition: width var(--slow) var(--ease);
}
.rv-dock .plan-list{
  list-style: none;
  margin: 11px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.rv-dock .plan-list li{
  position: relative;
  padding-left: 15px;
  font-size: 11px;
  font-weight: 600;
  line-height: 1.35;
  color: var(--ink);
}
.rv-dock .plan-list li::before{
  content: "";
  position: absolute;
  left: 0;
  top: 0.52em;
  width: 8px;
  height: 1.5px;
  background: var(--ink);
}
.rv-dock .tray-col{ display: flex; flex-direction: column; gap: 14px; min-width: 0; flex: 0 0 auto; }
.rv-dock .tray-col > .cap-hint, .rv-dock .tray-col > .cap-note, .rv-dock .tray-col > .size-est, .rv-dock .tray-col > .field-note{ margin: -8px 0 0; }
.rv-dock .tray-sec{
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.005em;
  color: var(--ink);
  /* No rule under it, and nothing under it to make room for.
     The rule was how a section announced itself when a section was just a
     title in a column. It is not any more: every section under it is a drawn
     box, so the line was a second boundary drawn 14px above the first one, and
     the two of them made a heading look like the top of a table. */
  padding-bottom: 0;
  border-bottom: 0;
  margin-bottom: 0;
}
.rv-dock .tray-col > .tray-sec:not(:first-child){ margin-top: 14px; }
.rv-dock .tray-col > .ws-group{ display: block; }
.rv-dock .tray-col .ws-group-body{ display: flex; flex-direction: column; gap: 14px; }
.rv-dock .ws-group-head .group-reset{
  margin: -4px 0;
  align-self: center;
  margin-right: -6px;
}
.rv-dock .border-row{ display: flex; flex-direction: column; align-items: stretch; gap: 6px; }
.rv-dock .border-div{ display: none; }
.rv-dock .border-row select.native-hidden{ display: none; }
.rv-dock .border-row .pillgroup{
  gap: 5px;
  transition: opacity var(--fast), transform var(--fast);
}
.rv-dock #border-field.border-off .border-div{ opacity: 0; }
.rv-dock #border-field.border-off .pillgroup:last-child{ display: none; }
.rv-dock .field-row > .field{ flex: 0 1 auto; }
.rv-dock .cap-hint, .rv-dock .cap-note{
  margin: 0;
  /* `assess` joins its reasons with newlines and means them: "4K needs a taller
     display" and "1440p is part of Quick" are two different facts about two
     different pills, and run together into a paragraph they read as one
     rambling sentence. */
  white-space: pre-line;
  font-size: 10.5px;
  line-height: 1.5;
}
.rv-dock .cap-hint, .rv-dock .cap-note{ font-weight: 400; }
.rv-dock .cap-hint{ color: var(--faint); }
.rv-dock .cap-hint:empty, .rv-dock .cap-note:empty{ display: none; }
.rv-dock .tray-col .ws-group-body > .cap-hint, .rv-dock .tray-col .ws-group-body > .cap-note, .rv-dock .tray-col .ws-group-body > .size-est, .rv-dock .tray-col .ws-group-body > .field-note{ margin: -8px 0 0; }
.rv-dock .field{ display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.rv-dock .field-label{ font-size: 11px; font-weight: 600; color: var(--ink); letter-spacing: 0.005em; }
:root[data-view="night"] #tray .tray-head, :root[data-theme="midnight"] .rv-dock #tray .tray-head, :root[data-view="night"] #tray .ws-group-head .tray-sec, :root[data-theme="midnight"] .rv-dock #tray .ws-group-head .tray-sec{ color: var(--accent); }
:root[data-view="night"] #tray .ws-group:not([open]) > .ws-group-head .tray-sec, :root[data-theme="midnight"] .rv-dock #tray .ws-group:not([open]) > .ws-group-head .tray-sec{
  color: color-mix(in srgb, var(--accent) 62%, transparent);
}
:root[data-view="night"] #tray .ws-group-head:hover .tray-sec, :root[data-theme="midnight"] .rv-dock #tray .ws-group-head:hover .tray-sec{ color: var(--accent-hi); }
:root[data-view="night"] #tray .ws-group-head::after, :root[data-theme="midnight"] .rv-dock #tray .ws-group-head::after{
  border-right-color: var(--accent);
  border-bottom-color: var(--accent);
}
.rv-dock .lay-label{ display: flex; align-items: center; gap: 6px; }
.rv-dock .lay-block{ gap: 8px; }
.rv-dock .lay-pair{
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px 6px;
}
.rv-dock .lay-pair > :first-child{ grid-column: span 2; }
.rv-dock .mirror-pill{ width: 100%; justify-content: center; }
.rv-dock .lay-block > .field{ gap: 5px; }
.rv-dock .field-label .qual{ font-weight: 500; color: var(--faint); }
.rv-dock .field-label .val{ font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }
.rv-dock .swatch-pills .pill-opt.active .sw-none{ box-shadow: none; }
.rv-dock .btn-primary.danger{ background: var(--red); }
.rv-dock .btn-primary.danger:hover{ background: color-mix(in srgb, var(--red) 88%, var(--ink)); }
.rv-dock .btn-primary{
  background: var(--accent);
  color: var(--on-accent);
  border: none;
  border-radius: 999px;
  padding: 11px 20px;
  font-size: 13px;
  font-weight: 600;
  transition: transform var(--fast), background var(--fast);
}
.rv-dock .btn-primary:hover{ transform: translateY(-1px); background: var(--accent-hi); }
.rv-dock .btn-primary:disabled{ opacity: 0.4; transform: none; }
.rv-dock .btn-quiet{
  background: var(--card);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 9px 16px;
  font-size: 12px;
  font-weight: 600;
  transition: background var(--fast), border-color var(--fast);
}
.rv-dock .btn-quiet:hover{ background: var(--well); border-color: var(--line-strong); }
.rv-dock .btn-quiet:disabled{ opacity: 0.4; }
.rv-dock .btn-quiet.danger{ color: var(--red); }
.rv-dock .btn-quiet.danger:hover{ background: rgba(201, 58, 58, 0.08); border-color: rgba(201, 58, 58, 0.35); }
.rv-dock .lib-top{
  flex: none;
  /* The header keeps its side inset — it is a title, not a section, and a
     title flush with a rounded frame reads as clipped. */
  padding: 14px 14px 0;
}
.rv-dock .tray-scroll{
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 14px), transparent 100%);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 14px), transparent 100%);
  padding-top: 14px;
  scroll-padding-top: 14px;
}
.rv-dock .lib-head{
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  /* No margin under the rule. `.tray-scroll` already opens with 14px of
     padding — which is not decoration, it is what keeps the first heading out
     of the 14px mask fade at the top of the scroller — so a margin here was a
     second 14 on top of it. Measured off a render: the drawer's title rule to
     the first heading was 37.5px where a section divider to a heading is 22.5,
     which is the "extra padding space below stylize line and background start"
     Franz filed on 30 Aug. Now 23.5 against 22.5. */
  padding-bottom: 9px;
  border-bottom: 1px solid var(--line);
}
.rv-dock .tray-head{
  font-family: var(--disp);
  font-size: 19px;
  font-weight: 700;
  font-style: normal;
  letter-spacing: -0.005em;
  line-height: 1.1;
  color: var(--ink);
}
.rv-dock .lib-head .tray-sec{ border: none; padding: 0; margin: 0; }
body.rv-dock-body .lib-bar .menu{ flex: 0 0 70px; min-width: 0; }
.rv-dock .lib-bar > *, .rv-dock .lib-bar .menu-trigger{ min-height: 28px; }
.rv-dock .lib-bar .tf{ display: flex; align-items: center; }
body.rv-dock-body .lib-bar .menu-trigger{
  width: 100%;
  justify-content: center;
  padding: 5px 8px;
  font-size: 11px;
  gap: 4px;
}
body.rv-dock-body .lib-bar .menu-pop{ padding: 4px; }
body.rv-dock-body .lib-bar .menu-item{ font-size: 11px; padding: 6px 9px; }
body.rv-dock-body .lib-bar .menu-value{
  max-width: 72px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rv-dock .edit-under .field{ width: 100%; }
body.rv-dock-body .bg-frame:fullscreen .fs-dock:not(.hidden){ display: block; }
.rv-dock .field.dimmed{ opacity: 0.45; }
.rv-dock .field.dimmed input[type="range"]{ pointer-events: none; }
.rv-dock .desk-foot .btn-primary, .rv-dock .desk-foot .btn-quiet{ width: auto; flex: 0 0 auto; }
.rv-dock .desk-foot .btn-primary{ padding-inline: 20px; }
.rv-dock .edit-side .ws-group-body{ display: flex; flex-direction: column; gap: 12px; }
.rv-dock .edit-side .ws-group-body > .ws-group-why{ margin: 0; }
.rv-dock .edit-side .tray-sec:not(:first-child){ margin-top: 8px; }
.rv-dock .edit-side .btn-primary, .rv-dock .edit-side .btn-quiet{ width: 100%; }
.rv-dock .edit-under .field-label{ font-size: 11px; }
.rv-dock .edit-under .btn-quiet{ align-self: flex-start; }
.rv-dock .tray .btn-primary, .rv-dock .tray .btn-quiet{ align-self: flex-start; }
.rv-dock .tray #drive-connect-form{ display: flex; flex-direction: column; gap: 14px; }
.rv-dock .tray .authchip{
  display: inline-flex;
  align-self: flex-start;
  margin: 0 0 6px;
}
.rv-dock .custom-chip .pill-opt{ border-top-right-radius: 0; border-bottom-right-radius: 0; }
.rv-dock .ws-swatches{
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 6px;
  margin-bottom: 12px;
}
.rv-dock .ws-sw{
  position: relative;
  aspect-ratio: 1;
  border: 0;
  border-radius: 7px;
  padding: 0;
  cursor: pointer;
  background-size: cover;
  background-position: center;
}
.rv-dock .ws-sw::before{
  content: "";
  position: absolute;
  inset: 0;
  border: 1.1px solid var(--pen-quiet);
  border-radius: inherit;
  filter: url(#rough-b);
  pointer-events: none;
}
.rv-dock .ws-sw.active{ outline: 2px solid var(--ink); outline-offset: 2px; }
.rv-dock .ws-scenes{
  /* Four across. The tiles are smaller than the three-across ones they replaced
     but still meaningfully larger than a flat-colour chip — a scene has to be
     *recognised*, which is a lower bar than judged, and four across clears it.
     With eleven scenes that fitted in three rows and nothing scrolled. With
     twenty-one it does not, and the grid still does not scroll on its own:
     the whole Backdrop group scrolls with the panel, so every tile is reached
     by the same gesture that reaches Composition rather than by a second
     scroll nested inside the first. A picker with its own scrollbar hides half
     its options behind an action; a long panel does not. */
  grid-template-columns: repeat(4, 1fr);
  gap: 8px 6px;
}
.rv-dock .ws-scenes .ws-sw{
  aspect-ratio: auto;
  background: none;
}
.rv-dock .ws-scenes .ws-sw::before{ display: none; }
.rv-dock .ws-sw-art{
  display: block;
  /* Fixed rather than `aspect-ratio`, so a row is a known height and the grid
     below never half-cuts one. 28, not 36: the backdrops became chips, so
     these are the only tiles left in the column and the one thing still asking
     for that much height. Small enough to sit with the chips, big enough that
     the stand-in still shows what the effect does — which is the whole reason
     this control kept its picture when the others gave theirs up. */
  height: 28px;
  border-radius: 7px;
  background-size: cover;
  background-position: center;
  position: relative;
}
.rv-dock .ws-sec .ws-sw-art{ height: 28px; }
.rv-dock .ws-sw-art::before{
  content: "";
  position: absolute;
  inset: 0;
  border: 1.1px solid var(--pen-quiet);
  border-radius: inherit;
  filter: url(#rough-b);
  pointer-events: none;
}
.rv-dock .ws-fxtile .ws-sw-art{ overflow: hidden; }
.rv-dock .ws-fxtile .ws-sw-art::after{
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
}
.rv-dock .ws-sw-name{
  display: block;
  margin-top: 4px;
  font-size: 9.5px;
  color: var(--mut);
  text-align: center;
  letter-spacing: 0.01em;
}
.rv-dock .ws-sw-named{ color: var(--mut); }
.rv-dock .ws-sw-named.active{ outline: none; }
.rv-dock .ws-sw-named.active .ws-sw-art{ outline: 2px solid var(--ink); outline-offset: 2px; }
.rv-dock .ws-sw-named.active .ws-sw-name{ color: var(--ink); }
.rv-dock .ws-imagepics{
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px 6px;
  max-height: calc(100cqw + 4px);
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 16px), transparent 100%);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 16px), transparent 100%);
}
.rv-dock .ws-imagepics:not(.is-scrolling){
  -webkit-mask-image: none;
  mask-image: none;
}
.rv-dock .ws-imagepics.ws-art{
  max-height: none;
  overflow: visible;
  -webkit-mask-image: none;
  mask-image: none;
}
.rv-dock .ws-imagepics.ws-art .ws-sw{ aspect-ratio: 16 / 9; border-radius: 8px; }
.rv-dock .ws-imagepics.ws-art{ position: relative; z-index: 0; }
.rv-dock .ws-imagepics.ws-art .ws-sw{ touch-action: none; user-select: none; -webkit-user-select: none; }
.rv-dock .ws-imagepics.ws-art .ws-sw[data-key]{ cursor: grab; }
.rv-dock .ws-imagepics.ws-art.is-dragging, .rv-dock .ws-imagepics.ws-art.is-dragging .ws-sw{ cursor: grabbing; }
.rv-dock .ws-imagepics.ws-art .ws-sw[data-key]:active{ transform: scale(0.97); }
.rv-dock .ws-imagepics.ws-art .ws-sw[data-key]{ transition: transform 0.12s var(--ease); }
.rv-dock .ws-imagepics.ws-art.is-dragging .ws-sw[data-key]:not(.ws-sw-lift):not(.ws-sw-gap){ opacity: 0.72; }
.rv-dock .ws-imagepics.ws-art .ws-sw-page{
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  /* Always the bottom-right cell, even on a short last page — the pointer
     holding a lifted tile over it is still over it after the page turns. */
  grid-column: 3;
  /* Filled, in the app's own two colours: ink on the ground, ground on the
     ink. Franz, 3 Sep: "the page 1&2 button backgrounds need to be like white
     and black". This is exactly the treatment a chosen pill already wears —
     `--ink` behind, `--paper` in front — which inverts by itself between
     Daylight and Midnight, so the cell is black-on-white in one and
     white-on-black in the other without a second rule. It is also the right
     answer for a cell sitting in a row of artwork: a tint reads as a
     twenty-third backdrop, a solid reads as a control. */
  /* White, with a black arrow, in both themes. Franz, 3 Sep: "white bg button
     and black arrow". Fixed values rather than tokens on purpose — `--paper`
     and `--ink` swap between Daylight and Midnight, and this cell is meant to
     read the same way in both: the one plain white key in a grid of pictures.
     The two values are Daylight's own paper and ink, so they are the app's
     colours and not new ones. */
  background: #f4f3ef;
  color: #131a24;
  font: inherit;
  transition: background var(--fast), transform var(--fast);
}
.rv-dock .ws-imagepics.ws-art .ws-sw-page::before{
  opacity: 1;
  border-color: rgba(19, 26, 36, 0.22);
}
.rv-dock .ws-imagepics.ws-art .ws-sw-page:hover{ background: #ffffff; }
.rv-dock .ws-imagepics.ws-art.is-dragging .ws-sw-page{
  background: var(--accent);
  color: var(--sink, #070d16);
}
.rv-dock .ws-imagepics.ws-art.is-dragging .ws-sw-page::before{
  opacity: 1;
  border: var(--none-edge);
  border-color: var(--accent);
  filter: none;
}
.rv-dock .ws-imagepics.ws-art.is-dragging .ws-sw-page .ws-page-arrow{
  animation: page-nudge 1.1s var(--ease) infinite;
}
.rv-dock .ws-imagepics.ws-art.is-dragging .ws-sw-page .ws-page-arrow.is-back{
  animation-name: page-nudge-back;
}
.rv-dock .ws-imagepics.ws-art .ws-sw-page.is-armed{
  background: var(--accent-hi);
  transform: scale(1.03);
}
.rv-dock .ws-page-arrow{
  width: 10px;
  height: 10px;
  border-right: 1.7px solid currentColor;
  border-bottom: 1.7px solid currentColor;
  transform: rotate(-45deg);
  filter: url(#rough-ink);
}
.rv-dock .ws-page-arrow.is-back{ transform: rotate(135deg); }
.rv-dock .ws-imagepics .ws-sw-gap{ background: var(--well) !important; }
.rv-dock .ws-imagepics .ws-sw-gap::before{ border: var(--none-edge); filter: none; }
.rv-dock .ws-imagepics .ws-sw-gap.active{ outline: none; }
.rv-dock .ws-imagepics .ws-sw-lift{
  position: absolute;
  z-index: 4;
  pointer-events: none;
  will-change: transform;
  aspect-ratio: auto;
  opacity: 1;
}
.rv-dock .ws-imagepics .ws-sw-lift::before{
  border-color: var(--accent);
  border-width: 1.6px;
  opacity: 1;
}
.rv-dock :is(.cam-bgpane, .ws-bgpane){ container-type: inline-size; }
.rv-dock :is(.cam-bgpane, .ws-bgpane) > :is(.ws-swatches, .chipgrid, .ws-imagepics) + .field{ margin-top: 14px; }
.rv-dock .ws-imagepics .ws-sw-art{ aspect-ratio: 1; height: auto; }
.rv-dock .ws-imagepics .ws-sw-named{ position: relative; }
.rv-dock .ws-imagepics .ws-sw-name{
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  margin: 0;
  padding: 3px 6px 4px;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.6), transparent);
  color: #fff;
  text-align: left;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  border-radius: 0 0 7px 7px;
}
.rv-dock .ws-sw-none .ws-sw-art, .rv-dock .ws-sw.ws-sw-none:not(.ws-sw-named){ background: var(--well); }
.rv-dock .ws-sw-none .ws-sw-art::after, .rv-dock .ws-sw.ws-sw-none:not(.ws-sw-named)::after{
  content: "";
  position: absolute;
  inset: 22% 18%;
  border: var(--none-edge);
  border-radius: 4px;
}
.rv-dock .ws-sw.ws-sw-none:not(.ws-sw-named)::after{ inset: 20%; border-radius: 3px; }
.rv-dock .ws-imagepics .ws-sw-none .ws-sw-art::after{ inset: 20%; border-radius: 4px; }
.rv-dock .ws-imagepics.ws-art .ws-sw-none{
  background: transparent;
}
.rv-dock .ws-imagepics.ws-art .ws-sw-none::before{
  border: var(--none-edge);
  filter: none;
}
.rv-dock .ws-imagepics.ws-art .ws-sw-none::after{
  content: "None";
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 0;
  font-family: var(--disp);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.004em;
  color: var(--mut);
  transition: color var(--fast);
}
.rv-dock .ws-imagepics.ws-art .ws-sw-none.active{ outline: none; }
.rv-dock .ws-imagepics.ws-art .ws-sw-none.active::before{
  border: 1.6px solid var(--ink);
}
.rv-dock .ws-imagepics.ws-art .ws-sw-none.active::after{ color: var(--ink); }
.rv-dock .ws-imagepics.ws-art .ws-sw-none:hover::after{ color: var(--ink); }
.rv-dock .ws-scenes .ws-sw-add .ws-sw-art, .rv-dock .ws-imagepics .ws-sw-add .ws-sw-art{
  background: var(--well);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  line-height: 1;
  color: inherit;
}
.rv-dock .ws-sec .ws-swatches + .ws-fxfamily.tray-sec, .rv-dock .edit-side .ws-swatches + .ws-fxfamily.tray-sec{ margin-top: 18px; }
.rv-dock .ws-group{
  display: block;
  position: relative;
}
.rv-dock .ws-group + .ws-group{ border-top: 1px solid var(--line); }
.rv-dock :is(.field, .field-row, .field-note, .ws-notice, .tf, .btn-quiet) + .ws-group{
  border-top: 1px solid var(--line);
}
.rv-dock .ws-group-head{
  display: flex;
  align-items: baseline;
  gap: 10px;
  list-style: none;
  cursor: pointer;
  margin: 0;
  padding: 14px 2px 12px;
  user-select: none;
  transition: color var(--fast);
}
.rv-dock .ws-group-head:hover .tray-sec{ color: var(--ink); }
.rv-dock .ws-group:not([open]) > .ws-group-head .tray-sec{ color: var(--mut); }
.rv-dock .tray-col > .ws-group + .ws-group, .rv-dock .edit-side > .ws-group + .ws-group{ margin-top: -14px; }
.rv-dock .ws-group-head::-webkit-details-marker{ display: none; }
.rv-dock .tray-col > .ws-group:first-child > .ws-group-head, .rv-dock .tray-col > .lib-head + .ws-group > .ws-group-head{ padding-top: 4px; }
.rv-dock .ws-group > .ws-group-head .tray-sec{
  border: 0;
  padding: 0;
  margin: 0;
  flex: 0 0 auto;
}
.rv-dock :is(#tray, #panel-settings, .ws-sec) .ws-group > .ws-group-head .tray-sec{
  font-family: var(--disp);
  font-size: 19px;
  font-weight: 700;
  font-style: normal;
  letter-spacing: -0.005em;
  line-height: 1.1;
}
.rv-dock :is(#tray, #panel-settings, .ws-sec) .ws-group > .ws-group-head{ padding-top: 18px; }
.rv-dock :is(#tray, #panel-settings) .tray-col > .ws-group:first-child > .ws-group-head, .rv-dock :is(#tray, #panel-settings) .tray-col > .lib-head + .ws-group > .ws-group-head{ padding-top: 6px; }
.rv-dock :is(#tray, #panel-settings) .ws-group-head::after{ width: 7px; height: 7px; }
.rv-dock .ws-group-say{
  flex: 1;
  min-width: 0;
  text-align: right;
  /* 11/500, not 10.5/400. This is the only text in the drawer a user reads
     *instead of* opening something, so it was the one line that could least
     afford to be the smallest and lightest thing on the page. Franz, 30 Aug:
     "the secondary text like when collapsed needs to be better". It stays in
     `--faint` rather than `--mut` — the heading beside it is `--mut` when the
     section is shut, and two greys of the same value on one line is a heading
     that stops looking like a heading. */
  font-size: 11px;
  font-weight: 500;
  color: var(--faint);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  transition: opacity var(--fast);
}
.rv-dock .ws-group[open] > .ws-group-head .ws-group-say{ opacity: 0; }
.rv-dock .ws-group-head::after{
  content: "";
  flex: 0 0 auto;
  /* Centred in the row, not sat on the text baseline. The head is a
     baseline-aligned flex row, and a box with no text in it baseline-aligns by
     its bottom edge — so the chevron sat low while the reset beside it was
     centred, and the two marks at the right-hand end of the row were on two
     different lines. Franz, 2 Sep: "the reset button in effects with proper
     alignment horizontally". One centre line for both. */
  align-self: center;
  width: 6px;
  height: 6px;
  margin-left: 2px;
  border-right: 1.3px solid var(--mut);
  border-bottom: 1.3px solid var(--mut);
  transform: rotate(-45deg) translate(-1px, 1px);
  transition: transform var(--fast);
  filter: url(#rough-ink);
}
.rv-dock .ws-group[open] > .ws-group-head::after{
  transform: rotate(45deg) translate(-2px, -2px);
}
.rv-dock .ws-group-body{ animation: group-in 0.14s var(--ease); padding: 0 2px 15px; }
.rv-dock .ws-off, .rv-dock .field.ws-off, .rv-dock .slider.ws-off{ opacity: 0.45; pointer-events: none; }
body.rv-dock-body.is-working .tray, body.rv-dock-body.is-working .controlbar{
  filter: blur(4px);
  opacity: 0.55;
  pointer-events: none;
  transition: opacity var(--slow), filter var(--slow);
}
