/* ───────────────────── The lane dock (2026-09-28) ─────────────────────
   Direction: "the mantel shelf" — the same painted hearth-lodge language as
   the Flash player's frame and the top bar. A tooled walnut plate with a brass
   edge, an ember line burning along its underside, and the lane's own colour
   glowing behind whichever lane is lit. It carries the lane pills on the left
   and the controls that decide what the grid shows on the right, with the
   filters actually in force spelled out underneath.

   Markup: media/dock.js (mount() turns a .vlane-bar / .glane-bar into this).
   Must load AFTER media/video-lanes.css and games/split.css — it overrides the
   plain flex row both of those give the bar.

   Two frames, one look. The CSS plate below is the floor: tokens only, so it
   survives any width and any number of rows. When the painted plate
   (media/dock/frame.webp) is present, dock.js probes it once and sets
   `html.hdock-art`, and the block at the end of this file lays the real art
   over the same box as a 9-slice — carved ends, brass straps, tiling middle.
   Change --dock-brass / --dock-ember and the whole shelf follows either way. */

.hdock {
  --dock-brass: 198, 160, 94;
  --dock-ember: 245, 158, 11;
  --dock-wood: 32, 24, 20;
  --dock-r: 16px;
  /* Whichever lane is lit paints this; the plate picks it up as a wash. */
  --dock-lane: var(--dock-ember);

  display: block;
  position: relative;
  isolation: isolate;
  margin: 0 0 18px;
  padding: 9px 12px;
  border: 1px solid rgba(var(--dock-brass), .34);
  border-radius: var(--dock-r);
  background:
    /* the lane's colour, breathed in behind the pills */
    radial-gradient(220px 80px at 8% -30%, rgba(var(--dock-lane), .16), transparent 72%),
    /* lamplight from above */
    linear-gradient(180deg, rgba(255, 236, 202, .07) 0%, transparent 42%),
    /* grain */
    repeating-linear-gradient(97deg, rgba(0, 0, 0, .16) 0 2px, rgba(255, 255, 255, .012) 2px 5px),
    linear-gradient(180deg, rgba(58, 44, 35, .72) 0%, rgba(var(--dock-wood), .94) 62%, rgba(14, 11, 9, .96) 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 233, 196, .16),
    inset 0 -1px 0 rgba(0, 0, 0, .55),
    0 10px 26px -18px rgba(0, 0, 0, .9);
}
/* The brass bead running round the inside edge of the plate. */
.hdock::before {
  content: '';
  position: absolute;
  inset: 3px;
  border: 1px solid rgba(var(--dock-brass), .22);
  border-radius: calc(var(--dock-r) - 4px);
  pointer-events: none;
}
/* The ember line along the shelf's underside — the fire it sits above. */
.hdock::after {
  content: '';
  position: absolute;
  left: 14px;
  right: 14px;
  bottom: -1px;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, transparent, rgba(var(--dock-lane), .55), transparent);
  filter: blur(.4px);
  pointer-events: none;
}

/* ONE row, always (Rober, 2026-10-05: "should never line break"). The rail
   used to wrap, and what wrapped depended on the lane: with seven pills the
   tools fell to a row of their own on one lane and a single pill fell under the
   others on the next. Nothing here wraps now. When the pills and the tools
   want more than the row holds, dock.js fit() measures and takes the next step
   down, the same steps on every lane:
     .fit-tight      the tools give up their word gutter to the pills: a
                     lane's name on show is worth more than 96px held empty
                     for a word that is not out. A word that opens then takes
                     its room from the tail of the pill box, under a fade
     .fit-lanes      every pill but the lit one is its icon; its name slides
                     out inline on hover (see below)
     .fit-scroll     last resort: the pills scroll sideways, under a fade on
                     whichever side still has pills out of sight
   Tried in that order (then lanes + tight together, then scroll).
   The tools have no rung of their own any more: they are icons at rest (see
   "Controls" below), so their words never cost the pills anything. A word
   that is dropped is hidden from the eye only, so the control keeps its name
   for a screen reader. */
.hdock-rail {
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  gap: 8px;
}
.hdock-lanes,
.hdock-tools {
  display: flex;
  align-items: center;
  flex-wrap: nowrap;
  gap: 8px;
}
/* The pills take whatever the row has left; the tools keep their own width at
   the far end. */
.hdock-lanes { flex: 1 1 auto; min-width: 0; }
.hdock-lanes > * { flex: none; }
/* The tools keep a gutter on their left the size of one open word (Controls,
   below), and spend it while a word is out: the plaque grows into the gutter,
   not into the pills, so hovering a tool never moves or clips a lane (Rober,
   2026-10-06: "i meant just stuff on right"). fit() measures the pill box
   with the gutter already taken, so a crowded row steps down a word's width
   earlier instead of lending the tools room it has not got. */
.hdock-tools {
  --dock-word-room: 96px;
  flex: none;
  margin-left: auto;
  padding-left: var(--dock-word-room);
  transition: padding-left .3s cubic-bezier(.2, .8, .2, 1);
}
.hdock-tools:has(> .hdock-btn:hover, > .hdock-btn:focus-visible) { padding-left: 0; }
/* The tray itself is drawn under "The tray", below the controls. */
.hdock .vlane-btn span,
.hdock .vlane-mode-btn { white-space: nowrap; }

/* A stepped-down pill is its icon, and its name slides out inline on hover —
   the same move as the tools' words (Rober, 2026-10-10, on a row of library
   icons: "on hover inline text names would be nice"). The pill becomes a grid
   whose word (and count, on Games) sits in a 0fr track: no width at rest, in
   the DOM for a screen reader, and on hover or keyboard focus the track opens
   and the word pushes out beside the icon. The tools give up their word gutter
   (--dock-word-room, below) while a pill's word is out, so the row does not
   overflow for a name up to the gutter's width. Touch has no hover: fit()
   sets the title attribute so the name is still one press away. */
:is(.hdock.fit-lanes .vlane-btn, .hdock .vlane-btn.is-yielding):not(.active) {
  display: inline-grid;
  grid-template-columns: auto 0fr 0fr;
  align-items: center;
  gap: 0;
  padding: 0 7px;
  transition: grid-template-columns .3s cubic-bezier(.2, .8, .2, 1), gap .3s cubic-bezier(.2, .8, .2, 1), padding .3s cubic-bezier(.2, .8, .2, 1),
    border-color .2s ease, background .2s ease, color .2s ease, transform .2s ease, box-shadow .2s ease;
}
:is(.hdock.fit-lanes .vlane-btn, .hdock .vlane-btn.is-yielding):not(.active) > :is(span, small) {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  opacity: 0;
  transition: opacity .18s ease;
}
:is(.hdock.fit-lanes .vlane-btn, .hdock .vlane-btn.is-yielding):not(.active):focus-visible {
  grid-template-columns: auto 1fr auto;
  gap: 8px;
  padding: 0 14px 0 7px;
}
:is(.hdock.fit-lanes .vlane-btn, .hdock .vlane-btn.is-yielding):not(.active):focus-visible > :is(span, small) { opacity: 1; }
@media (hover: hover) {
  :is(.hdock.fit-lanes .vlane-btn, .hdock .vlane-btn.is-yielding):not(.active):hover {
    grid-template-columns: auto 1fr auto;
    gap: 8px;
    padding: 0 14px 0 7px;
  }
  :is(.hdock.fit-lanes .vlane-btn, .hdock .vlane-btn.is-yielding):not(.active):hover > :is(span, small) { opacity: 1; }
  /* The room for the word: the tools' gutter, which exists for exactly one
     open word at a time. Their frame follows so no tool is left outside it. */
  .hdock.fit-lanes:has(.hdock-lanes .vlane-btn:not(.active):hover) .hdock-tools { padding-left: 3px; }
  .hdock.fit-lanes:has(.hdock-lanes .vlane-btn:not(.active):hover) .hdock-tools::before { left: 0; }
}
.hdock.fit-lanes:has(.hdock-lanes .vlane-btn:not(.active):focus-visible) .hdock-tools { padding-left: 3px; }
.hdock.fit-lanes:has(.hdock-lanes .vlane-btn:not(.active):focus-visible) .hdock-tools::before { left: 0; }
/* The tight rung: no gutter, so the frame starts at the tray's own edge. A
   tool's word still opens; it takes its room from the tail of the pill box,
   which clips under the short fade further down for as long as it is out. */
.hdock.fit-tight .hdock-tools { --dock-word-room: 0px; }
/* dock.js fit() reads each rung with everything already at its final width:
   the gutter eases, and so does a pill giving up its word, and a rung read
   mid-ease looked too narrow, was skipped, and the row ended up scrolling
   with room to spare (the cut-off pills of 2026-10-10). */
.hdock.hdock-measuring .hdock-tools,
.hdock.hdock-measuring .hdock-tools::before,
.hdock.hdock-measuring .vlane-btn,
.hdock.hdock-measuring .vlane-btn > * { transition: none !important; }
/* …and as the row is at REST, whatever the pointer is on: a refit that lands
   while a tool's word or a pill's name is out (a click changes the sort's
   name, say) must not pick a rung that only fits for as long as it is. */
.hdock.hdock-measuring .hdock-tools { padding-left: calc(var(--dock-word-room) + 3px) !important; }
.hdock.hdock-measuring .hdock-btn-lbl { grid-template-columns: 0fr !important; padding: 0 !important; }
.hdock.hdock-measuring:is(.fit-lanes) .vlane-btn:not(.active),
.hdock.hdock-measuring .vlane-btn.is-yielding:not(.active) { grid-template-columns: auto 0fr 0fr !important; gap: 0 !important; padding: 0 7px !important; }
/* The way back to the split screen, seated in the rail by dock.js: it keeps
   its own width whatever the pills are doing. */
.hdock-rail > .vlane-split { flex: none; }
/* The scroll box is taller than the pills, pulled back by the same margin: a
   box clipped at the pills' own edge would shave the lit pill's glow, the
   hover lift and the focus ring. A side fades only while pills are out of
   sight on that side (dock.js markMore sets .hdock-more-l / -r as it
   scrolls), so the first and the last pill are never dimmed at rest. The way
   back to the split screen is not in this box at all: dock.js seats it in the
   rail (Rober, 2026-10-10: "weird back button", "vr seems to be cut off too"). */
.hdock.fit-scroll .hdock-lanes {
  --more-l: #000;
  --more-r: #000;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  margin: -8px -3px;
  padding: 8px 3px;
  mask-image: linear-gradient(90deg, var(--more-l), #000 26px, #000 calc(100% - 26px), var(--more-r));
}
.hdock.fit-scroll.hdock-more-l .hdock-lanes { --more-l: transparent; }
.hdock.fit-scroll.hdock-more-r .hdock-lanes { --more-r: transparent; }
.hdock.fit-scroll .hdock-lanes::-webkit-scrollbar { display: none; }
/* On the tight rung a pill's own word (it still slides out on hover) has no
   gutter to grow into, so the box clips it under a short fade for as long as
   it is out, the same way a tool's long word is handled below. */
.hdock.fit-tight:not(.fit-scroll) .hdock-lanes {
  overflow: clip;
  margin: -8px -3px;
  padding: 8px 3px;
}
.hdock.fit-tight:not(.fit-scroll):has(.hdock-lanes .vlane-btn:not(.active):hover, .hdock-lanes .vlane-btn:not(.active):focus-visible) .hdock-lanes {
  mask-image: linear-gradient(90deg, #000 calc(100% - 30px), transparent);
}
/* A word longer than the tools' gutter (above) would still take the last few
   pixels from the pill box, so for as long as a word is open the box clips
   under a short fade, with the same pulled-back edge, and gives the room back
   the moment the pointer leaves. Not in fit-scroll: that box scrolls already,
   and swapping its overflow would drop its position. */
.hdock:not(.fit-scroll):has(.hdock-tools > .hdock-btn:hover, .hdock-tools > .hdock-btn:focus-visible) .hdock-lanes {
  overflow: clip;
  margin: -8px -3px;
  padding: 8px 3px;
  mask-image: linear-gradient(90deg, #000 calc(100% - 30px), transparent);
}

/* ── Plaques ──
   Everything that sits ON the shelf is one shape: a small-radius plaque cut
   into the wood, with a brass hairline and a lit top edge. Capsules were the
   first cut and they read as web pills stuck onto a painted board — the frame
   is joinery, and joinery has corners. One rule drives the lane pills (built
   by video-lanes.js / games/split.js / images.js), the dock's own controls and
   the filter chips, so they cannot drift apart. */
.hdock .vlane-split,
.hdock .vlane-btn,
.hdock-btn {
  border-radius: var(--dock-plaque, 9px);
  border: 1px solid rgba(var(--dock-brass), .3);
  background:
    linear-gradient(180deg, rgba(255, 236, 202, .05), rgba(0, 0, 0, .18)),
    rgba(6, 5, 4, .58);
  box-shadow:
    inset 0 1px 0 rgba(255, 233, 196, .1),
    inset 0 -1px 0 rgba(0, 0, 0, .5);
}
.hdock .vlane-split:hover,
.hdock .vlane-btn:hover,
.hdock-btn:hover {
  border-color: rgba(var(--dock-brass), .66);
  background:
    linear-gradient(180deg, rgba(255, 236, 202, .1), rgba(0, 0, 0, .16)),
    rgba(14, 10, 7, .62);
}
/* ── The library tray ──
   The libraries a person made (TV Shows, Movies, …) and the + that makes
   another are ONE framed thing, like the tools at the far end: a brass-edged
   tray let into the shelf with the pills as segments parted by hairlines
   (Rober, 2026-10-10: "frame the actual main tv libraries in their own
   unified framing"). video-lanes.js builds the box (.vlane-libs); Hearth's
   own lanes stay loose plaques beside it, so the frame is the divider and
   the rule that used to part the two groups steps aside. The lit library
   keeps its lane colour; a segment has no edge of its own otherwise. */
.hdock .vlane-libs {
  position: relative;
  display: flex;
  align-items: center;
  flex: none;
  gap: 2px;
  padding: 3px;
  border-radius: var(--dock-plaque, 9px);
  border: 1px solid rgba(var(--dock-brass), .36);
  background:
    linear-gradient(180deg, rgba(0, 0, 0, .32), rgba(0, 0, 0, .1)),
    rgba(6, 5, 4, .55);
  box-shadow:
    inset 0 1px 0 rgba(0, 0, 0, .55),
    inset 0 -1px 0 rgba(255, 233, 196, .07),
    0 1px 0 rgba(255, 233, 196, .06);
}
.hdock .vlane-libs > * { flex: none; position: relative; }
.hdock .vlane-libs > .vlane-btn { min-height: 32px; border-radius: calc(var(--dock-plaque, 9px) - 3px); }
.hdock .vlane-libs > .vlane-add { width: 34px; height: 32px; border-radius: calc(var(--dock-plaque, 9px) - 3px); }
.hdock .vlane-libs > .vlane-btn:not(.active),
.hdock .vlane-libs > .vlane-add {
  border-color: transparent;
  background: transparent;
  box-shadow: none;
}
.hdock .vlane-libs > .vlane-btn:not(.active):hover,
.hdock .vlane-libs > .vlane-add:hover {
  border-color: transparent;
  background: linear-gradient(180deg, rgba(255, 236, 202, .13), rgba(255, 236, 202, .05));
  transform: none;
}
/* The hairline between two segments; none beside the lit one, which has an
   edge of its own. */
.hdock .vlane-libs > * + *::before {
  content: '';
  position: absolute;
  left: -2px;
  top: 6px;
  bottom: 6px;
  width: 1px;
  background: linear-gradient(180deg, transparent, rgba(var(--dock-brass), .34) 25%, rgba(var(--dock-brass), .34) 75%, transparent);
  pointer-events: none;
}
.hdock .vlane-libs > .active::before,
.hdock .vlane-libs > .active + *::before { display: none; }
.hdock .vlane-libs + .vlane-sep,
.hdock .vlane-sep:has(+ .vlane-libs) { display: none; }

/* The lit lane: its own colour, and a deeper seat rather than a glow halo. */
.hdock .vlane-btn.active {
  border-color: rgba(var(--lane-rgb), .8);
  background:
    linear-gradient(180deg, rgba(var(--lane-rgb), .26), rgba(var(--lane-rgb), .1)),
    rgba(6, 5, 4, .5);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .14),
    0 0 14px -4px rgba(var(--lane-rgb), .55);
}
/* The custom/Hearth divider, over the dock's darker metals. */
.hdock .vlane-sep {
  background: linear-gradient(180deg, transparent, rgba(255, 255, 255, .22) 30%, rgba(255, 255, 255, .22) 70%, transparent);
}

/* ── Controls ──
   Icons at rest (Rober, 2026-10-06: "this takes a lot of room, make this
   icons, and inline hover shows text"). Each control is a square plaque the
   size of the back arrow and the pin; its word is in the DOM the whole time
   (a screen reader reads it, and the finder lists it) but drawn in a 0fr
   grid track, so it has no width. Hover or keyboard focus opens the track
   and the word slides out of the plaque beside its icon, inline, pushing the
   neighbours rather than floating over them — the plaque grows into a
   labelled one for as long as the pointer rests on it. `.hdock-btn-lbl` is the
   track and `.hdock-btn-word` the thing in it: a bare text node could not be
   given `min-width: 0`, and without that the track never closes. Touch has no
   hover, so the title attribute keeps saying what each one is. */
.hdock-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 40px;
  min-height: 38px;
  max-width: 260px;
  padding: 0 9px;
  color: var(--text-dim);
  font: 600 13px/1 inherit;
  cursor: pointer;
  transition: border-color .2s ease, background .2s ease, color .2s ease, transform .2s ease, box-shadow .2s ease;
}
.hdock-btn:hover {
  color: var(--text);
  transform: translateY(-1px);
}
.hdock-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.hdock-btn-lbl {
  display: grid;
  grid-template-columns: 0fr;
  opacity: 0;
  transition: grid-template-columns .3s cubic-bezier(.2, .8, .2, 1), opacity .18s ease, padding .3s cubic-bezier(.2, .8, .2, 1);
}
.hdock-btn-word {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.hdock-btn:focus-visible .hdock-btn-lbl {
  grid-template-columns: 1fr;
  opacity: 1;
  padding: 0 4px 0 8px;
}
@media (hover: hover) {
  .hdock-btn:hover .hdock-btn-lbl {
    grid-template-columns: 1fr;
    opacity: 1;
    padding: 0 4px 0 8px;
  }
}
.hdock-ico {
  width: 20px;
  height: 20px;
  flex: none;
  object-fit: contain;
  transition: transform .35s cubic-bezier(.3, 1.6, .5, 1);
}
.hdock-ico.round { border-radius: 50%; object-fit: cover; }
.hdock-btn:hover .hdock-ico { transform: scale(1.12) rotate(-5deg); }

/* ── The tray ──
   The controls read as ONE framed thing (Rober, 2026-10-06: "make them feel
   like stuff on right are one framed"): a brass-edged tray let into the
   shelf, the icons sitting in it as segments parted by hairlines, not a row
   of loose plaques. The frame is the tools box's own ::before, painted behind
   the segments and starting AFTER the word gutter, so the gutter stays
   outside the frame; when a word opens the frame grows left with it, the
   same ease as the word. A segment has no edge of its own — a state that
   needs one (Favourites on, the pin pressed, Sources open) still gets it
   from its own rule below, which is why this block sits above them. */
.hdock-tools {
  position: relative;
  isolation: isolate;
  gap: 2px;
  padding-top: 3px;
  padding-right: 3px;
  padding-bottom: 3px;
  padding-left: calc(var(--dock-word-room) + 3px);
}
.hdock-tools:has(> .hdock-btn:hover, > .hdock-btn:focus-visible) { padding-left: 3px; }
.hdock-tools::before {
  content: '';
  position: absolute;
  z-index: -1;
  inset: 0 0 0 var(--dock-word-room);
  border-radius: var(--dock-plaque, 9px);
  border: 1px solid rgba(var(--dock-brass), .36);
  background:
    linear-gradient(180deg, rgba(0, 0, 0, .32), rgba(0, 0, 0, .1)),
    rgba(6, 5, 4, .55);
  box-shadow:
    inset 0 1px 0 rgba(0, 0, 0, .55),
    inset 0 -1px 0 rgba(255, 233, 196, .07),
    0 1px 0 rgba(255, 233, 196, .06);
  pointer-events: none;
  transition: left .3s cubic-bezier(.2, .8, .2, 1);
}
.hdock-tools:has(> .hdock-btn:hover, > .hdock-btn:focus-visible)::before { left: 0; }
.hdock-tools > .hdock-btn {
  position: relative;
  min-height: 32px;
  border-radius: calc(var(--dock-plaque, 9px) - 3px);
  border-color: transparent;
  background: transparent;
  box-shadow: none;
}
/* Hovered, the segment lights where it sits; it does not lift out of the tray. */
.hdock-tools > .hdock-btn:hover {
  border-color: transparent;
  background: linear-gradient(180deg, rgba(255, 236, 202, .13), rgba(255, 236, 202, .05));
  transform: none;
}
/* The hairline between two segments: on the later one, in the 2px gap. A
   hidden control (Play on a media dock) parts nothing. */
.hdock-tools > .hdock-btn:not(.hidden, [hidden]) ~ .hdock-btn:not(.hidden, [hidden])::before {
  content: '';
  position: absolute;
  left: -2px;
  top: 7px;
  bottom: 7px;
  width: 1px;
  background: linear-gradient(180deg, transparent, rgba(var(--dock-brass), .42) 25%, rgba(var(--dock-brass), .42) 75%, transparent);
  pointer-events: none;
}

/* ── The drawer ──
   At rest the tray is ONE button, a chest of drawers at the end of the row
   (Rober, 2026-10-10: "maybe this should be one button that opens up to
   others"). Pointing at the tray, tabbing into it, or pressing the handle
   (.is-open, dock.js) slides the others out to its left, each to an icon's
   width; a pointed-at tool shows its word as a tag hung under it (below),
   not inline. The handle is the
   last child, so it stays under the pointer while the tray grows away from
   it. Shut, the tools have no width but stay in the tab order: focus landing
   on one opens the tray. There is no word gutter any more: the tray is 44px
   at rest and the pills have the rest of the row, and while it is open it
   takes its room from the tail of the pill box, under the short fade.
   Closing waits a quarter second, so a pointer cutting a corner on its way
   to a tool does not shut the drawer in its face. At 900px and under the
   tools have a row of their own and stay out (the handle is hidden there).
   The header knob stays OUT of the drawer, beside the handle: it is the one
   way back to the top bar and the tabs (Rober, the same evening: "no chevron
   button to bring back top bar"). When the drawer opens, dock.js fit() folds
   the names of the lanes nearest it, one at a time, until the rest fits
   beside it (.is-yielding on the pill, the same shape as a .fit-lanes pill),
   so the pills move out of its way; the fade is only for a row that is
   already icons and still too long. */
.hdock-more { display: none; }
@media (min-width: 901px) {
  .hdock-tools.hdock-drawer {
    --dock-word-room: 0px;
    gap: 0;
    transition: gap .3s cubic-bezier(.2, .8, .2, 1) .26s, padding-left .3s cubic-bezier(.2, .8, .2, 1);
  }
  .hdock-drawer > .hdock-more { display: inline-flex; }
  .hdock-drawer > .hdock-btn:not(.hdock-more, .hdock-fold, .hdock-stay) {
    max-width: 0;
    min-width: 0;
    padding-left: 0;
    padding-right: 0;
    border-left-width: 0;
    border-right-width: 0;
    overflow: hidden;
    opacity: 0;
    pointer-events: none;
    transition:
      max-width .3s cubic-bezier(.2, .8, .2, 1) .26s, min-width .3s cubic-bezier(.2, .8, .2, 1) .26s,
      padding .3s cubic-bezier(.2, .8, .2, 1) .26s, opacity .2s ease .26s,
      border-color .2s ease, background .2s ease, color .2s ease;
  }
  .hdock-drawer:is(:hover, :focus-within, .is-open) { gap: 2px; transition-delay: 0s; }
  .hdock-drawer:is(:hover, :focus-within, .is-open) > .hdock-btn:not(.hdock-more, .hdock-fold, .hdock-stay) {
    max-width: 44px;
    min-width: 40px;
    padding-left: 9px;
    padding-right: 9px;
    border-left-width: 1px;
    border-right-width: 1px;
    opacity: 1;
    pointer-events: auto;
    transition-delay: 0s;
  }
  /* The word hangs UNDER the tool as a tag, and the row keeps its width
     (Rober, 2026-10-12: "if i move my mouse to that and try to continue left
     the menu closes, so i can neaver easily get to like favorites"). Inline,
     as on the rest of the dock, the tray grows leftwards from the handle, so
     every tool the pointer crossed slid its word out and shoved the ones
     still to come further left; and leaving a tool whose word was out folded
     it back, the tools to its left slid right past the pointer, and with the
     pointer off the tray the drawer shut. The tag is out of the flow, so
     nothing in the row moves under the pointer. */
  .hdock-drawer:is(:hover, :focus-within, .is-open) > .hdock-btn:not(.hdock-more, .hdock-fold, .hdock-stay):is(:hover, :focus-visible) { overflow: visible; }
  .hdock-drawer > .hdock-btn:not(.hdock-more, .hdock-fold, .hdock-stay) .hdock-btn-lbl {
    position: absolute;
    z-index: 3;
    top: calc(100% + 7px);
    left: 50%;
    display: block;
    width: max-content;
    max-width: 220px;
    padding: 5px 9px;
    border: 1px solid rgba(var(--dock-brass), .5);
    border-radius: 7px;
    background: linear-gradient(180deg, rgba(34, 28, 22, .98), rgba(16, 13, 10, .98));
    box-shadow: 0 6px 18px -6px rgba(0, 0, 0, .8), inset 0 1px 0 rgba(255, 236, 202, .08);
    color: var(--text);
    font-size: 12px;
    opacity: 0;
    transform: translate(-50%, -3px);
    pointer-events: none;
    transition: opacity .14s ease, transform .14s ease;
  }
  .hdock-drawer:is(:hover, :focus-within, .is-open) > .hdock-btn:not(.hdock-more, .hdock-fold, .hdock-stay):focus-visible .hdock-btn-lbl {
    padding: 5px 9px;
    opacity: 1;
    transform: translate(-50%, 0);
  }
  @media (hover: hover) {
    /* A beat late, so a pointer passing over on its way to another tool does
       not flash every tag it crosses. */
    .hdock-drawer:is(:hover, :focus-within, .is-open) > .hdock-btn:not(.hdock-more, .hdock-fold, .hdock-stay):hover .hdock-btn-lbl {
      padding: 5px 9px;
      opacity: 1;
      transform: translate(-50%, 0);
      transition-delay: .12s;
    }
  }
  /* The open tray keeps the pointer a little past its edges: a hand drifting
     off the 32px row on the way to a tool does not shut it. */
  .hdock-tools.hdock-drawer:is(:hover, :focus-within, .is-open)::after {
    content: '';
    position: absolute;
    z-index: -2;
    inset: -10px -4px -10px -14px;
  }
  /* The hairline sits inside the segment's own edge here: a shut segment
     clips, and a rule drawn in the gap would be cut off with it. None before
     the handle while it stands alone. */
  .hdock-drawer > .hdock-btn:not(.hidden, [hidden]) ~ .hdock-btn:not(.hidden, [hidden])::before { left: 0; }
  .hdock-drawer:not(:hover, :focus-within, .is-open) > .hdock-fold::before,
  .hdock-drawer:not(:hover, :focus-within, .is-open, :has(> .hdock-fold)) > .hdock-stay::before,
  .hdock-drawer:not(:hover, :focus-within, .is-open, :has(> .hdock-fold, > .hdock-stay)) > .hdock-more::before { display: none; }
  /* Shut, the two that stay out stand a hair apart like any two segments. */
  .hdock-drawer:not(:hover, :focus-within, .is-open) > :is(.hdock-fold, .hdock-stay) { margin-right: 2px; }
  /* fit() measures the row with the drawer shut, whatever the pointer is on. */
  .hdock.hdock-measuring .hdock-drawer { gap: 0 !important; transition: none !important; }
  .hdock.hdock-measuring .hdock-drawer > .hdock-btn:not(.hdock-more, .hdock-fold, .hdock-stay) {
    max-width: 0 !important;
    min-width: 0 !important;
    padding-left: 0 !important;
    padding-right: 0 !important;
    border-left-width: 0 !important;
    border-right-width: 0 !important;
    transition: none !important;
  }
  /* …and, for the second question fit() asks (do the names fit BESIDE the open
     drawer?), with it fully out. The more specific of the two wins. */
  .hdock.hdock-measuring.hdock-measuring-open .hdock-drawer { gap: 2px !important; }
  .hdock.hdock-measuring.hdock-measuring-open .hdock-drawer > .hdock-btn:not(.hdock-more, .hdock-fold, .hdock-stay) {
    max-width: 44px !important;
    min-width: 40px !important;
    padding-left: 9px !important;
    padding-right: 9px !important;
    border-left-width: 1px !important;
    border-right-width: 1px !important;
  }
  /* The pill box gives the open drawer its room and takes it back. */
  .hdock:not(.fit-scroll):has(.hdock-drawer:is(:hover, :focus-within, .is-open)) .hdock-lanes {
    overflow: clip;
    margin: -8px -3px;
    padding: 8px 3px;
    mask-image: linear-gradient(90deg, #000 calc(100% - 30px), transparent);
  }
}
/* The handle: lit while the drawer is out, and brass while Favourites is
   narrowing the shelf, which is otherwise out of sight in there. */
.hdock-drawer:is(:hover, :focus-within, .is-open) > .hdock-more {
  background: linear-gradient(180deg, rgba(255, 236, 202, .13), rgba(255, 236, 202, .05));
}
.hdock-more .hdock-ico { width: 22px; height: 22px; }
.hdock-drawer:is(:hover, :focus-within, .is-open) > .hdock-more .hdock-ico { transform: translateY(1px) scale(1.08); }
.hdock-tools > .hdock-more.is-set {
  border-color: rgba(var(--dock-brass), .85);
  background:
    linear-gradient(180deg, rgba(var(--dock-brass), .3), rgba(var(--dock-brass), .1)),
    rgba(6, 5, 4, .5);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .18), 0 0 16px -5px rgba(var(--dock-brass), .6);
}
@media (prefers-reduced-motion: reduce) {
  .hdock-tools.hdock-drawer, .hdock-drawer > .hdock-btn { transition: none !important; }
}

/* ── Rips ──
   The one tool besides the header knob that stays out of the drawer
   (dock.js buildRips): the painted rip crate, with a number let into its
   corner. Brass counts the rips still running, and the crate breathes while
   they do; red counts failures nobody has looked at yet. No number, nothing
   to report. */
.hdock-tools > .hdock-rips { overflow: visible; }
.hdock-rips-n {
  position: absolute;
  z-index: 2;
  top: 1px;
  right: 1px;
  min-width: 17px;
  height: 17px;
  padding: 0 4px;
  border-radius: 9px;
  box-sizing: border-box;
  font-size: 10.5px;
  font-weight: 700;
  line-height: 17px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.01em;
  white-space: nowrap;
  color: #1c140a;
  background: linear-gradient(180deg, rgb(var(--dock-brass)), color-mix(in srgb, rgb(var(--dock-brass)) 72%, #000));
  box-shadow: 0 0 0 1.5px rgba(8, 6, 4, .92), 0 2px 6px -2px rgba(0, 0, 0, .8);
  pointer-events: none;
  transform-origin: 70% 30%;
  animation: hdock-rips-pop .32s cubic-bezier(.3, 1.6, .5, 1);
}
.hdock-rips-n[hidden] { display: none; }
.hdock-rips.has-failed .hdock-rips-n {
  color: #fff6f4;
  background: linear-gradient(180deg, #ef5b52, #b8322b);
  box-shadow: 0 0 0 1.5px rgba(8, 6, 4, .92), 0 0 12px -2px rgba(239, 91, 82, .75);
}
.hdock-tools > .hdock-rips.has-failed {
  background: linear-gradient(180deg, rgba(239, 91, 82, .16), rgba(239, 91, 82, .04));
}
.hdock-rips.is-running:not(.has-failed) .hdock-ico { animation: hdock-rips-breathe 2.2s ease-in-out infinite; }
@keyframes hdock-rips-breathe {
  0%, 100% { transform: none; filter: none; }
  50% { transform: translateY(-1px) scale(1.07); filter: brightness(1.18) drop-shadow(0 0 4px rgba(255, 170, 70, .55)); }
}
@keyframes hdock-rips-pop {
  from { transform: scale(.4); opacity: 0; }
  to { transform: none; opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .hdock-rips .hdock-ico, .hdock-rips-n { animation: none !important; }
}

/* ─── the pin ───────────────────────────────────────────────────────────────
   A knob at the right end of the tools, beside the header knob and the same
   shape: icon only. Pressed, every dock holds the top of its lane while the
   shelf scrolls under it (dock.js setPinned). */
.hdock-btn.hdock-pin {
  justify-content: center;
  min-width: 38px;
  padding: 0 9px;
  -webkit-app-region: no-drag;
}
.hdock-pin .hdock-ico {
  width: 22px;
  height: 22px;
  opacity: .78;
  filter: saturate(.6);
  transform: rotate(38deg);
  transition: transform .35s cubic-bezier(.3, 1.6, .5, 1), opacity .2s ease, filter .2s ease;
}
/* Pushed in: the pin stands upright, at full colour, in a lit seat. */
.hdock-pin[aria-pressed='true'],
html.hdock-art .hdock.vlane-bar .hdock-pin[aria-pressed='true'] {
  color: var(--text);
  border-color: rgba(var(--dock-ember), .72);
  background:
    linear-gradient(180deg, rgba(var(--dock-ember), .22), rgba(var(--dock-ember), .07)),
    rgba(6, 5, 4, .5);
  box-shadow:
    inset 0 2px 5px rgba(0, 0, 0, .55),
    inset 0 -1px 0 rgba(255, 233, 196, .08);
}
.hdock-pin[aria-pressed='true'] .hdock-ico { opacity: 1; filter: none; transform: rotate(0deg) translateY(1px); }
@media (hover: hover) {
  .hdock-btn.hdock-pin:hover .hdock-ico { opacity: 1; filter: none; transform: rotate(22deg) scale(1.1); }
  .hdock-btn.hdock-pin[aria-pressed='true']:hover .hdock-ico { transform: rotate(-8deg) translateY(-1px) scale(1.08); }
}
.hdock-pin-mark { height: 0; margin: 0; padding: 0; pointer-events: none; }
/* The lane scrolls inside .main, whose own padding the sticky edge is measured
   from: pull the dock up through it so no strip of the shelf shows above. */
.hdock.is-pinned {
  position: sticky;
  top: calc(4px - var(--page-gutter, 0px));
  z-index: 6;
}
/* The shelf passes UNDER a pinned dock, so its tiles must not compete with it.
   A tile is not a stacking context, so every z-indexed piece inside one (the
   frame's pillars and plaque, the tile bars, badges, the delete veil: 4 to 11)
   was ordered against the dock directly, and the Videos lanes' dock sits at 3
   (.has-drawer). Pinned, the grid's tiles painted over the canister and cut it
   into pieces (Rober, 2026-10-09). Raising the dock cannot win that: the Steam
   tiles' run buttons sit at 10-11, level with the topbar, which must stay above
   the dock when chrome-fold slides it over the page. So each grid keeps its
   tiles' layers to itself instead and paints as one layer under the dock and
   the Sources drawer. */
section.main .grid { isolation: isolate; }
/* TV Shows / Movies set their bar to position: relative later in the cascade
   (vlib.css), which silently switched the pin off there. */
.vlib-main > .vlane-bar.is-pinned { position: sticky; }

/* ── The header (2026-10-14) ──
   A pinned dock is the lane's header (dock.js seatHead). It stays where it
   rests rather than rising into the scroller's top padding, so nothing moves
   when the shelf starts to scroll, and its scroller (.hdock-headed) gets:
     --hdock-pt / --hdock-px   the scroller's own top / side padding
     --hdock-head              how far the header reaches: padding, dock and
                               the dock's bottom margin, so it ends where the
                               shelf starts.
   The band is the scroller's ::before, sticky at its top edge and taking no
   room (its margins cancel its height). Under the dock (6, or 3 with the
   Sources drawer) and the TV / Movies toolbar (4), over the shelf, which
   paints as one layer (.grid above). Clear at rest; frosted once the shelf
   passes under (.hdock-head-under). */
.hdock-headed > .hdock.is-pinned { top: 0; }
.hdock-headed { scroll-padding-top: calc(var(--hdock-head) + 8px); }
.hdock-headed::before {
  content: '';
  display: block;
  position: sticky;
  top: calc(-1 * var(--hdock-pt));
  z-index: 2;
  height: var(--hdock-head);
  margin: calc(-1 * var(--hdock-pt)) calc(-1 * var(--hdock-px)) calc(var(--hdock-pt) - var(--hdock-head));
  pointer-events: none;
  background: linear-gradient(180deg, rgba(10, 11, 16, .96), rgba(10, 11, 16, .86));
  -webkit-backdrop-filter: blur(14px) saturate(1.15);
  backdrop-filter: blur(14px) saturate(1.15);
  box-shadow: 0 16px 28px -16px rgba(0, 0, 0, .85);
  opacity: 0;
  transition: opacity .22s ease;
}
.hdock-headed.hdock-head-under::before { opacity: 1; }
/* The scrollbar begins under the header. A track margin is the only way to
   start a scroller's bar lower, and it exists only on the -webkit- scrollbar,
   which Chromium ignores while scrollbar-color is set — and :root sets it
   (media/profiles.css), and it inherits. So this scroller drops back to auto
   and draws the same thumb itself. Firefox has no such scrollbar and keeps
   the plain full-height one. */
@supports selector(::-webkit-scrollbar) {
  .hdock-headed { scrollbar-color: auto; scrollbar-width: auto; }
  .hdock-headed::-webkit-scrollbar { width: 12px; }
  .hdock-headed::-webkit-scrollbar-track { background: transparent; margin-top: var(--hdock-head); }
  .hdock-headed::-webkit-scrollbar-thumb {
    min-height: 40px;
    border: 3px solid transparent;
    border-radius: 6px;
    background: var(--profile-scroll-thumb) padding-box;
  }
  .hdock-headed::-webkit-scrollbar-thumb:hover { background: var(--profile-scroll-hover) padding-box; }
}
@media (prefers-reduced-motion: reduce) {
  .hdock-headed::before { transition: none; }
}
/* Off its resting place: the shelf is passing underneath. */
.hdock.is-pinned.is-stuck {
  box-shadow:
    0 14px 26px -12px rgba(0, 0, 0, .78),
    0 2px 0 rgba(0, 0, 0, .35);
}
/* The painted docks are a shape, not a box: their shadow follows the art. */
html.hdock-art .hdock.is-pinned.is-stuck {
  box-shadow: none;
  filter: drop-shadow(0 12px 12px rgba(0, 0, 0, .7));
}
@media (max-width: 560px) {
  .hdock-btn.hdock-pin { padding: 0 12px; }
}
@media (prefers-reduced-motion: reduce) {
  .hdock-pin .hdock-ico { transition: none; }
}

/* Favourites: gold when only, ash-grey when hiding them. The two states have
   to be told apart at a glance from across the room, so they are different
   colours AND different icons, never the same pill with a tick. */
.hdock-fav[data-state='only'] {
  color: #fde7c0;
  border-color: rgba(var(--dock-brass), .85);
  background:
    linear-gradient(180deg, rgba(var(--dock-brass), .3), rgba(var(--dock-brass), .1)),
    rgba(6, 5, 4, .5);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .18), 0 0 16px -5px rgba(var(--dock-brass), .6);
}
.hdock-fav[data-state='hide'] {
  color: #cbd5e1;
  border-color: rgba(148, 163, 184, .55);
  background:
    linear-gradient(180deg, rgba(148, 163, 184, .18), rgba(71, 85, 105, .1)),
    rgba(6, 5, 4, .5);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .12);
}
/* Updates (games docks): ember-to-red when the shelf is narrowed to the games
   with a build waiting — the sidebar's "Outdated only" chip wears the same
   gradient, so one colour means one thing — and the plain lit look when the
   shelf is ordered by recent installs, since that is a sort, not a cut. */
.hdock-upd[data-state='needs'] {
  color: #fde0d2;
  border-color: rgba(239, 68, 68, .6);
  background:
    linear-gradient(180deg, rgba(var(--dock-ember), .32), rgba(239, 68, 68, .12)),
    rgba(6, 5, 4, .5);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .16), 0 0 16px -5px rgba(239, 68, 68, .55);
}
.hdock-upd[data-state='recent'] {
  color: var(--text);
  border-color: rgba(var(--dock-brass), .7);
  background:
    linear-gradient(180deg, rgba(var(--dock-brass), .22), rgba(var(--dock-brass), .06)),
    rgba(6, 5, 4, .5);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .14);
}
/* A count on the resting button reads as a nudge, not a setting: ember text. */
.hdock-upd[data-state='all']:not([data-count='']) .hdock-btn-word { color: rgb(var(--dock-ember)); }
.hdock-sort .hdock-btn-lbl { color: var(--text); }
/* Play mode (games docks): it names a setting, like Sort, so it reads lit.
   Moonlight is the mode that leaves this page, and wears the brass edge. */
.hdock-play .hdock-btn-lbl { color: var(--text); }
.hdock-play[data-mode='moonlight'] { border-color: rgba(var(--dock-brass), .7); }

/* The filter shelf's chevron, seated at the head of the rail (dock.js
   seatFilters) — the same square plaque as the back arrow beside it. It points
   at the shelf: right to pull it out, left (turned) to put it away. Open, it
   wears the lit edge so it is plain which control the open shelf belongs to. */
.hdock-btn.hdock-filters {
  flex: none;
  justify-content: center;
  width: 40px;
  min-height: 40px;
  padding: 0;
  -webkit-app-region: no-drag;
}
.hdock-filters svg { flex: none; display: block; transition: transform .32s cubic-bezier(.3, 1.45, .5, 1); }
.hdock-filters[aria-expanded='true'] svg { transform: rotate(180deg); }
@media (hover: hover) {
  .hdock-filters:hover svg { transform: translateX(1.5px); }
  .hdock-filters[aria-expanded='true']:hover svg { transform: rotate(180deg) translateX(1.5px); }
}
.hdock .hdock-btn.hdock-filters[aria-expanded='true'] {
  color: var(--accent-warm);
  border-color: rgba(var(--dock-ember), .7);
}
body.hearth-immersive .hdock-filters { display: none; }
@media (prefers-reduced-motion: reduce) {
  .hdock-filters svg { transition: none; }
}

/* ── Active filters ── */
.hdock-chips {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 9px;
  padding-top: 9px;
  border-top: 1px solid rgba(var(--dock-brass), .16);
}
.hdock-chips.hidden { display: none; }
.hdock-chips-head {
  font: 600 11px/1 inherit;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: rgba(var(--dock-brass), .8);
  margin-right: 2px;
}
.hdock-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 30px;
  padding: 0 9px;
  border: 1px solid rgba(var(--dock-brass), .3);
  border-radius: calc(var(--dock-plaque, 9px) - 2px);
  background: rgba(6, 5, 4, .55);
  box-shadow: inset 0 1px 0 rgba(255, 233, 196, .08);
  color: var(--text);
  font: 600 12px/1 inherit;
  cursor: pointer;
  max-width: 260px;
  transition: border-color .2s ease, background .2s ease, color .2s ease;
}
.hdock-chip:hover {
  border-color: rgba(248, 113, 113, .6);
  background: rgba(248, 113, 113, .12);
}
.hdock-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.hdock-chip .hdock-ico { width: 16px; height: 16px; }
.hdock-chip-lbl { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hdock-chip-x { color: var(--text-dim); font-size: 11px; }
.hdock-chip:hover .hdock-chip-x { color: #fca5a5; }
.hdock-chip-clear {
  color: rgba(var(--dock-brass), .95);
  border-style: dashed;
}

/* ── Quick find ──
   One typed box over every way a shelf can be narrowed AND everything on it.
   It is a dialog over the grid rather than a dropdown off the button: the list
   is long, it is searched, and it stays open while several filters are stacked.

   Direction: the same painted hearth-lodge as the dock it belongs to — a brass
   bead inside a walnut case, an ember wash off the top, carved group rules. The
   one thing it does NOT share with the dock is a border-image frame: this panel
   changes height with every keystroke, and a 9-slice's carved ends would stretch
   differently on every one. Tokens only, so it holds any shape. */
.hqp-scrim {
  position: fixed;
  inset: 0;
  z-index: 3000;
  display: grid;
  /* Dead centre, both axes. It used to hang at 10vh with its list floored at
     240px, which on a tall screen read as a panel pinned to the ceiling above a
     stripe of empty page. */
  place-items: center;
  padding: 16px;
  background:
    radial-gradient(60% 50% at 50% 42%, rgba(120, 70, 20, .16), transparent 70%),
    rgba(6, 5, 8, .66);
  backdrop-filter: blur(4px) saturate(.9);
  animation: hqp-in .16s ease-out;
}
.hqp {
  --hqp-brass: 198, 160, 94;
  --hqp-ember: 245, 158, 11;
  width: min(760px, 100%);
  /* Sized to its content and centred, so a two-result search is a small panel
     in the middle rather than a tall one with a hole in it. */
  max-height: min(78vh, 760px);
  display: flex;
  flex-direction: column;
  position: relative;
  border: 1px solid rgba(var(--hqp-brass), .42);
  border-radius: 18px;
  overflow: hidden;
  background:
    radial-gradient(520px 180px at 50% -12%, rgba(var(--hqp-ember), .16), transparent 70%),
    repeating-linear-gradient(97deg, rgba(0, 0, 0, .13) 0 2px, rgba(255, 255, 255, .01) 2px 5px),
    linear-gradient(180deg, rgba(38, 29, 23, .985), rgba(13, 11, 14, .99));
  box-shadow:
    0 40px 90px -34px rgba(0, 0, 0, .96),
    0 0 0 1px rgba(0, 0, 0, .5),
    inset 0 1px 0 rgba(255, 233, 196, .16);
  animation: hqp-rise .18s cubic-bezier(.2, .9, .3, 1);
}
/* The brass bead inside the case — the dock's own edge, at this scale. */
.hqp::before {
  content: '';
  position: absolute;
  inset: 4px;
  border: 1px solid rgba(var(--hqp-brass), .17);
  border-radius: 14px;
  pointer-events: none;
  z-index: 2;
}
@keyframes hqp-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes hqp-rise { from { transform: translateY(10px) scale(.99); opacity: 0; } to { transform: none; opacity: 1; } }

.hqp-head {
  display: flex;
  align-items: center;
  gap: 12px;
  flex: none;
  position: relative;
  padding: 15px 17px;
  border-bottom: 1px solid rgba(var(--hqp-brass), .22);
  background: linear-gradient(180deg, rgba(255, 236, 202, .055), transparent);
}
/* The ember line under the search box, the same one that burns along the
   underside of the dock's shelf. Anchored to the head's own bottom edge — it
   used to be offset from the panel by a hard-coded header height, which is a
   number that stops being true the moment the head gains a row. */
.hqp-head::after {
  content: '';
  position: absolute;
  left: 18px;
  right: 18px;
  bottom: -1px;
  height: 2px;
  border-radius: 2px;
  background: linear-gradient(90deg, transparent, rgba(var(--hqp-ember), .5), transparent);
  filter: blur(.5px);
  pointer-events: none;
}
.hqp-head .hdock-ico { opacity: .92; }
.hqp-input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: none;
  color: var(--text);
  /* 16px minimum: anything smaller and iOS zooms the page on focus. */
  font: 500 17px/1.3 inherit;
  outline: none;
}
.hqp-input::placeholder { color: rgba(148, 137, 124, .85); }
/* The native search decorations are a blue system glyph in the middle of a
   painted panel; the palette has its own Esc and its own scrim. */
.hqp-input::-webkit-search-cancel-button,
.hqp-input::-webkit-search-decoration { -webkit-appearance: none; appearance: none; }
.hqp-scope {
  flex: none;
  padding: 5px 11px;
  border: 1px solid rgba(var(--hqp-brass), .38);
  border-radius: 8px;
  background: linear-gradient(180deg, rgba(var(--hqp-brass), .18), rgba(0, 0, 0, .2));
  box-shadow: inset 0 1px 0 rgba(255, 233, 196, .18);
  color: #fde7c0;
  font: 700 11px/1 inherit;
  letter-spacing: .1em;
  text-transform: uppercase;
}
.hqp-list {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  overscroll-behavior: contain;
  padding: 7px;
  scrollbar-width: thin;
  scrollbar-color: var(--profile-scroll-thumb) transparent;
}
.hqp-list::-webkit-scrollbar { width: 10px; }
.hqp-list::-webkit-scrollbar-thumb {
  border: 3px solid transparent;
  border-radius: 8px;
  background: var(--profile-scroll-thumb) padding-box;
}
.hqp-list::-webkit-scrollbar-thumb:hover { background: var(--profile-scroll-hover) padding-box; }

/* A carved rule running out of each heading to the edge — the shelf's own
   joinery, and what keeps a long mixed list readable as sections. */
.hqp-group {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 13px 9px 6px;
}
.hqp-group:first-child { padding-top: 5px; }
.hqp-group-t {
  flex: none;
  font: 700 10px/1 inherit;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: rgba(var(--hqp-brass), .82);
}
.hqp-group::after {
  content: '';
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, rgba(var(--hqp-brass), .28), transparent);
}

.hqp-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 46px;
  padding: 5px 10px;
  border: 1px solid transparent;
  border-radius: 11px;
  background: none;
  color: var(--text);
  font: 500 14px/1.2 inherit;
  text-align: left;
  cursor: pointer;
  transition: background .13s ease, border-color .13s ease;
}
.hqp-row:hover { background: rgba(255, 255, 255, .05); }
.hqp-row.sel {
  background:
    linear-gradient(90deg, rgba(var(--hqp-ember), .2), rgba(var(--hqp-ember), .07) 60%, transparent),
    rgba(255, 255, 255, .03);
  border-color: rgba(var(--hqp-ember), .5);
  box-shadow: inset 0 1px 0 rgba(255, 233, 196, .1);
}
.hqp-row.on .hqp-lbl { color: #fde7c0; }
.hqp-row:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

/* ── Row art ──
   One box whatever goes in it (cover, poster, four-up mosaic, painted glyph),
   so a list that mixes a sort with a game still scans as a single column. The
   art rows are taller because a 3:2 cover at row height is unreadable. */
.hqp-art {
  flex: none;
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  border-radius: 8px;
  overflow: hidden;
}
.hqp-row.art .hqp-art { width: 62px; height: 42px; }
.hqp-glyph { background: rgba(255, 255, 255, .035); box-shadow: inset 0 0 0 1px rgba(var(--hqp-brass), .14); }
.hqp-shot,
.hqp-mosaic {
  background: rgba(0, 0, 0, .55);
  box-shadow: inset 0 0 0 1px rgba(var(--hqp-brass), .3), inset 0 1px 0 rgba(255, 233, 196, .1);
}
.hqp-shot img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hqp-shot.blank { background: rgba(255, 255, 255, .04); }
.hqp-mosaic {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: 1fr 1fr;
  gap: 1px;
  /* .hqp-art centres its one child; a mosaic's cells are empty spans, so
     inheriting that centring sized every one of them to zero and the tile
     rendered as a black square. They must fill their track. */
  place-items: stretch;
}
.hqp-mosaic.few { grid-template-columns: 1fr; grid-template-rows: 1fr; }
.hqp-mosaic-cell { background-size: cover; background-position: center 30%; }

.hqp-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.hqp-lbl { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hqp-sub {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--text-dim);
  font-size: 12px;
}
.hqp-on {
  flex: none;
  padding: 3px 8px;
  border-radius: 6px;
  background: rgba(var(--hqp-ember), .22);
  box-shadow: inset 0 0 0 1px rgba(var(--hqp-ember), .4);
  color: #fde7c0;
  font: 700 10px/1 inherit;
  letter-spacing: .08em;
  text-transform: uppercase;
}
/* Only on the highlighted row: "Enter opens this one" is the answer to the one
   question an item row raises, and a column of arrows is noise. */
.hqp-go { flex: none; color: rgba(var(--hqp-brass), .7); font-size: 13px; opacity: 0; }
.hqp-row.sel .hqp-go { opacity: 1; }

.hqp-none {
  display: grid;
  justify-items: center;
  gap: 4px;
  padding: 44px 18px;
  text-align: center;
}
.hqp-none .hdock-ico { opacity: .4; margin-bottom: 6px; }
.hqp-none-t { margin: 0; color: var(--text); font: 600 15px/1.3 inherit; }
.hqp-none-s { margin: 0; color: var(--text-dim); font: 400 13px/1.4 inherit; max-width: 34ch; }

.hqp-foot {
  display: flex;
  align-items: center;
  gap: 14px;
  flex: none;
  padding: 10px 15px;
  border-top: 1px solid rgba(var(--hqp-brass), .2);
  background: linear-gradient(180deg, transparent, rgba(0, 0, 0, .3));
  color: var(--text-dim);
  font: 500 11px/1 inherit;
}
.hqp-hint { display: inline-flex; align-items: center; gap: 5px; }
.hqp-hint-t { color: var(--text-dim); }
/* Real keycaps rather than the glyph inline in a sentence: the footer is a
   legend, and a legend reads faster when the key looks like a key. */
.hqp-key {
  display: inline-grid;
  place-items: center;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  border: 1px solid rgba(var(--hqp-brass), .35);
  border-radius: 5px;
  background: linear-gradient(180deg, rgba(255, 236, 202, .09), rgba(0, 0, 0, .3));
  box-shadow: inset 0 1px 0 rgba(255, 233, 196, .14), 0 1px 0 rgba(0, 0, 0, .5);
  color: rgba(253, 231, 192, .92);
  font: 600 10px/1 inherit;
}
.hqp-count { margin-left: auto; color: rgba(var(--hqp-brass), .72); font-weight: 600; }
/* The switch to the shelf's own search bar (dock.js "The search bar"). */
.hqp-mode {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex: none;
  min-height: 28px;
  padding: 0 10px 0 7px;
  border: 1px solid rgba(var(--hqp-brass), .3);
  border-radius: 7px;
  background: linear-gradient(180deg, rgba(255, 236, 202, .07), rgba(0, 0, 0, .25));
  color: rgba(253, 231, 192, .9);
  font-family: inherit;
  font-size: 11px;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease, color .15s ease;
}
.hqp-mode:hover { border-color: rgba(var(--hqp-ember), .65); color: #fff; }
.hqp-mode:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.hqp-mode .hdock-ico { width: 16px; height: 16px; }

/* ── The search bar ──
   A real field in the rail, between the lanes and the tools, when the
   search bar is switched on (dock.js setInline; .hdock-inline on the host).
   It is the tray the tools sit in, cut as an inset slot: the same brass
   edge and dark well, so the row still reads as one shelf with two fittings
   on it. It gives up width before the lanes give up their names (a high
   shrink weight against the pills' 1), down to a width that still shows a
   word and a half of placeholder. The ember ring is its focus state; the
   caret is in it, so the input's own outline is not drawn twice. */
.hdock-find[hidden] { display: none; }
.hdock-find {
  position: relative;
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 6 300px;
  min-width: 168px;
  height: 38px;
  padding: 0 4px 0 10px;
  border: 1px solid rgba(var(--dock-brass), .36);
  border-radius: var(--dock-plaque, 9px);
  background:
    linear-gradient(180deg, rgba(0, 0, 0, .34), rgba(0, 0, 0, .12)),
    rgba(6, 5, 4, .6);
  box-shadow:
    inset 0 1px 0 rgba(0, 0, 0, .55),
    inset 0 -1px 0 rgba(255, 233, 196, .07),
    0 1px 0 rgba(255, 233, 196, .06);
  cursor: text;
  transition: border-color .18s ease, box-shadow .18s ease, background .18s ease;
}
.hdock-find:hover { border-color: rgba(var(--dock-brass), .55); }
.hdock-find:focus-within {
  border-color: rgba(var(--dock-ember), .75);
  background:
    linear-gradient(180deg, rgba(var(--dock-ember), .08), rgba(0, 0, 0, .1)),
    rgba(6, 5, 4, .7);
  box-shadow:
    inset 0 1px 0 rgba(0, 0, 0, .55),
    0 0 0 3px rgba(var(--dock-ember), .16),
    0 0 18px -6px rgba(var(--dock-ember), .55);
}
.hdock-find-ico { flex: none; width: 20px; height: 20px; opacity: .78; transition: opacity .18s ease; pointer-events: none; }
.hdock-find:focus-within .hdock-find-ico { opacity: 1; }
.hdock-q {
  flex: 1 1 auto;
  min-width: 0;
  height: 100%;
  padding: 0;
  border: 0;
  outline: 0;
  background: transparent;
  color: var(--text);
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  text-overflow: ellipsis;
}
.hdock-q::placeholder { color: rgba(253, 231, 192, .45); opacity: 1; }
.hdock-q::-webkit-search-decoration,
.hdock-q::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; display: none; }
.hdock-find-x,
.hdock-find-k {
  flex: none;
  display: inline-grid;
  place-items: center;
  height: 28px;
  border: 1px solid transparent;
  border-radius: calc(var(--dock-plaque, 9px) - 3px);
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.hdock-find-x[hidden] { display: none; }
.hdock-find-x { width: 28px; font-family: inherit; font-size: 12px; font-weight: 600; line-height: 1; }
.hdock-find-x:hover { background: rgba(255, 236, 202, .09); color: var(--text); }
.hdock-find-k { padding: 0 3px; }
.hdock-find-k kbd {
  display: inline-grid;
  place-items: center;
  height: 20px;
  padding: 0 6px;
  border: 1px solid rgba(var(--dock-brass), .35);
  border-radius: 5px;
  background: linear-gradient(180deg, rgba(255, 236, 202, .09), rgba(0, 0, 0, .3));
  box-shadow: inset 0 1px 0 rgba(255, 233, 196, .14), 0 1px 0 rgba(0, 0, 0, .5);
  color: rgba(253, 231, 192, .85);
  font-family: inherit;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .04em;
  line-height: 1;
  white-space: nowrap;
}
.hdock-find-k:hover kbd { border-color: rgba(var(--dock-ember), .7); color: #fff; }
.hdock-find-x:focus-visible,
.hdock-find-k:focus-visible { outline: 2px solid var(--accent); outline-offset: -1px; }
/* The list of best matches hangs under the bar (lookup.js, .klook-drop): over
   the shelf, not in the row, so it never moves a tile. The dock lifts above
   the grid and a pinned header's band while it is down. */
.hdock:has(.hdock-find .klook:not([hidden])) { z-index: 7; }
.hdock-find > .klook-drop {
  position: absolute;
  top: calc(100% + 8px);
  right: -4px;
  width: min(440px, calc(100vw - 32px));
  margin: 0;
  background:
    linear-gradient(180deg, rgba(255, 233, 196, .04), transparent 40%),
    rgba(14, 11, 10, .97);
  box-shadow:
    inset 0 1px 0 rgba(255, 233, 196, .06),
    0 18px 40px -12px rgba(0, 0, 0, .85);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  cursor: default;
}

/* ── Narrow ── */
/* Two rows by design, not by overflow: the pills (with the shelf's chevron) on
   the first, the controls sharing the second. Each row is still one line. */
@media (max-width: 900px) {
  .hdock-rail { flex-wrap: wrap; }
  .hdock-lanes { flex: 1 1 0; }
  /* A row of their own: a word opening here touches no pill, so no gutter. */
  .hdock-tools { margin-left: 0; width: 100%; padding-left: 3px; }
  .hdock-tools::before { left: 0; }
  .hdock-btn { flex: 1 1 0; min-width: 0; justify-content: center; }
  .hdock-btn.hdock-filters { flex: none; }
  /* The search bar takes the second row whole, the tools the third: a field
     sharing a row with six icons is left too narrow to read what was typed. */
  .hdock-find { flex: 1 1 100%; min-width: 0; order: 1; }
  .hdock-tools { order: 2; }
  .hdock-find > .klook-drop { left: -4px; right: -4px; width: auto; }
}
@media (max-width: 560px) {
  .hdock { padding: 8px; }
  /* Touch: 44px minimum, the target is the icon. */
  .hdock-btn { padding: 0 12px; min-height: 44px; }
  .hdock-chip { min-height: 34px; }
  .hqp-scrim { padding: 8px; }
  .hqp { max-height: 88vh; border-radius: 14px; }
  .hqp-head { padding: 12px 13px; gap: 9px; }
  /* The scope chip repeats what the placeholder already says, and on a phone
     it costs the search box a third of its width. */
  .hqp-scope { display: none; }
  .hqp-row { min-height: 52px; }
  .hqp-row.art .hqp-art { width: 56px; height: 38px; }
  .hqp-foot { gap: 10px; flex-wrap: wrap; }
  .hqp-count { margin-left: 0; width: 100%; }
  /* Touch: a 44px field, and 16px type so iOS does not zoom on focus. */
  .hdock-find { height: 44px; }
  .hdock-q { font-size: 16px; }
  .hdock-find-x { width: 36px; height: 36px; }
  /* No keyboard to press it with: the chip is the door to Find, so it says so. */
  .hdock-find-k kbd { font-size: 11px; height: 26px; }
}

@media (prefers-reduced-motion: reduce) {
  .hdock-btn, .hdock-btn-lbl, .hdock-tools, .hdock-tools::before, .hdock-ico, .hdock-chip, .hqp-row,
  .hdock-find, .hdock-find-ico, .hdock-find-x, .hdock-find-k, .hqp-mode,
  .hdock.fit-lanes .vlane-btn, .hdock.fit-lanes .vlane-btn > :is(span, small),
  .hdock .vlane-btn.is-yielding, .hdock .vlane-btn.is-yielding > :is(span, small) { transition: none; }
  .hqp-scrim, .hqp { animation: none; }
}

/* ── The painted plate ──
   Only once dock.js has proved the art loads (html.hdock-art), so a missing
   file can never leave the dock as a bare 3px line — the trap the Flash
   mantel's border-width fallback taught us. --dock-band tracks the art's own
   slice numbers: border-width and border-image-slice must move together or the
   carved ends stop lining up with the shelf. `round` on the middles, since the
   plate's grain is a repeat; `stretch` would smear it at wide widths. */
html.hdock-art .hdock {
  /* Source: 1324x238, brass caps 95px wide, beads 26px / 30px. Every number
     below is that source scaled by 0.36 — slice and border-width MUST move
     together or the carved ends stop lining up with the wood. */
  --dock-band-t: 9px;
  --dock-band-b: 11px;
  --dock-band-x: 34px;
  border-style: solid;
  border-width: var(--dock-band-t) var(--dock-band-x) var(--dock-band-b);
  border-image: url('dock/frame.webp') 26 95 30 95 fill stretch;
  border-radius: 0;
  /* Sized so the content area is the art's own middle band at the same 0.36
     (182px * 0.36 ≈ 66px): the end caps then render at their true aspect
     instead of being squeezed by a shorter box. */
  padding: 13px 12px;
  background: none;
  /* NOTHING that paints a rectangle. An inset shadow is clipped to the padding
     BOX, so its square corners showed straight through the art's rounded ends
     as a visible outline — the same trap as a border-box background on a
     painted frame. The wood in the art is already dark; it needs no help. */
  box-shadow: none;
}
/* The art brings its own bead and its own ember; the CSS plate's would double up. */
html.hdock-art .hdock::before,
html.hdock-art .hdock::after { display: none; }

/* ── The sources drawer (2026-09-29) ──
   The source tray, re-hung as a drawer under the dock (media/common.js,
   wireSourceDrawer). The dock stands OVER it (z-index), and the drawer's top
   edge is tucked --drawer-tuck up behind the dock's bottom edge, so it never
   has a top edge of its own that shows: it reads as a board sliding out from
   beneath the shelf. Inset from the dock's ends so the dock's carved caps
   stay proud of it. The opening animation is a plain translate: the dock
   hides the part that has not come out yet, so no clip-path is needed (and
   none would let the handle hang past the drawer's edge). */
.hdock.has-drawer {
  --drawer-gap: 18px;   /* the dock's usual margin: its Sources control lives on it now */
  z-index: 3;
  margin-bottom: var(--drawer-gap);
}
.media-sources.is-drawer {
  --drawer-tuck: 12px;
  --drawer-rise: 48px;  /* how far up under the dock it starts */
  position: relative;
  z-index: 1;
  margin: calc(-1 * (var(--drawer-gap, 34px) + var(--drawer-tuck))) 30px 40px;
  padding-top: calc(var(--drawer-tuck) + 10px);
  border-top: 0;
  border-radius: 0 0 14px 14px;
  box-shadow:
    /* the dock's shadow falling across the drawer's throat */
    inset 0 18px 14px -12px rgba(0, 0, 0, .82),
    inset 0 -3px 0 rgba(0, 0, 0, .3),
    inset 0 -1px 0 rgba(var(--source-brass), .24),
    0 12px 20px -14px #000;
}
.media-sources.is-drawer:not(.open) { display: none; }

@keyframes source-drawer-in {
  from { transform: translateY(calc(-1 * var(--drawer-rise))); opacity: 0; }
  45%  { opacity: 1; }
  to   { transform: none; opacity: 1; }
}
@keyframes source-drawer-out {
  from { transform: none; opacity: 1; }
  to   { transform: translateY(calc(-1 * var(--drawer-rise))); opacity: 0; }
}
@keyframes source-plaque-in {
  from { opacity: 0; transform: translateY(-9px) scale(.94); }
  to   { opacity: 1; transform: none; }
}
/* A little past its seat and back: the pop. */
.media-sources.is-drawer.opening { animation: source-drawer-in .46s cubic-bezier(.2, 1.28, .36, 1) both; }
.media-sources.is-drawer.closing { animation: source-drawer-out .22s cubic-bezier(.5, 0, .75, .35) both; }
/* The plaques drop onto the board one after another as it comes out. */
.media-sources.is-drawer.opening :is(.media-sources-all, .media-source-nav, .media-source-chip, .media-sources-icons, .media-sources-expand) {
  animation: source-plaque-in .34s cubic-bezier(.25, 1.35, .4, 1) both;
  animation-delay: calc(110ms + var(--i, 0) * 34ms);
}
.media-sources.is-drawer.opening :is(.media-sources-icons, .media-sources-expand) { --i: 9; }

/* The pull: the dock's Sources control (media/common.js wireSourceDrawer), a
   .hdock-btn like Favourites, Sort and Find, carrying the painted brass arrow.
   Open, the arrow turns to point back up into the dock. Shut on a filtered
   lane it wears that source's icon and an ember edge, like every "a filter is
   on" cue, because the grid is missing things and this is what explains why. */
.source-pull[hidden] { display: none; }
.hdock-btn.source-pull .source-pull-arrow {
  filter: drop-shadow(0 1px 1.5px rgba(0, 0, 0, .85));
  transition: transform .34s cubic-bezier(.3, 1.45, .5, 1);
}
.hdock-btn.source-pull:hover .source-pull-arrow { transform: translateY(2px); }
.hdock-btn.source-pull.is-open .source-pull-arrow { transform: rotate(180deg); }
.hdock-btn.source-pull.is-open:hover .source-pull-arrow { transform: rotate(180deg) translateY(2px); }
.source-pull-badge { display: block; flex: none; width: 16px; height: 16px; border-radius: 4px; }
.source-pull-badge[hidden] { display: none; }
.hdock-btn.source-pull.is-open { color: var(--text); border-color: rgba(var(--dock-brass), .66); }
.hdock-btn.source-pull.is-filtered:not(.is-open) {
  color: var(--text);
  border-color: rgba(var(--dock-ember), .72);
  box-shadow: inset 0 1px 0 rgba(255, 233, 196, .1), 0 0 14px -4px rgba(var(--dock-ember), .6);
}

@media (max-width: 560px) {
  .media-sources.is-drawer { margin-left: 8px; margin-right: 8px; }
}
@media (prefers-reduced-motion: reduce) {
  .media-sources.is-drawer.opening,
  .media-sources.is-drawer.closing,
  .media-sources.is-drawer.opening :is(.media-sources-all, .media-source-nav, .media-source-chip, .media-sources-icons, .media-sources-expand) { animation: none; }
  .source-pull-arrow { transition: none; }
}

/* ── The video lanes' dock: a film canister (2026-09-29) ──
   Rober: the walnut plate "is great for games … make the dock look like its a
   long film reel … more of a film cylinder … make it more obviously modern".
   So on the Videos tab — every .vlane-bar: Videos, VR, Toons / Anime and the
   TV / Movies libraries; Games and Images keep the walnut — the plate is a
   modern machined
   35mm film canister — gunmetal, knurled caps, an amber ring at each end —
   lying on its side, stretched to the dock's length, and the sources
   drawer under it is the FILM, pulled out of the canister's slit.

   Art (media/dock/, cut from one generated canister, 252px tall):
     can-l.webp     108x252  knob, knurled cap, amber ring  (cap ends at .33H)
     can-r.webp      86x252  amber ring, knurled cap
     can-body.webp   16x252  ONE averaged column of the plain body, so it
                             stretches to any length with nothing to smear
   The three canister layers are all 100% of the box's height; the body is
   inset by the dock's own height (--dock-h-px, kept current by dock.js) so it
   starts under the left cap and ends under the right one at ANY height — a
   wrapped dock on a phone is simply a fatter canister. Padding is fixed, not
   derived from the height, so the art can never feed back into the layout.
   The canister body spans 5%–97% of the box and its slot sits at 87–92%;
   the paddings keep the pills on the metal, above the slot.

   It was #view-videos alone until 2026-10-05. The lane bar has since grown
   into one row of pills over four views, and pressing a pill swapped the whole
   plate, walnut to gunmetal and back, under the same pills (Rober: "it changes
   visually too"). One tab, one plate. */
html.hdock-art .hdock.vlane-bar {
  --dock-h-px: 96px;
  min-height: 96px;
  border: 0;
  border-image: none;
  padding: 10px 48px 22px 58px;
  background:
    url('dock/can-l.webp') left center / auto 100% no-repeat,
    url('dock/can-r.webp') right center / auto 100% no-repeat,
    url('dock/can-body.webp') calc(var(--dock-h-px) * .37) center / calc(100% - var(--dock-h-px) * .67) 100% no-repeat;
  filter: drop-shadow(0 8px 10px rgba(0, 0, 0, .55));
}
html.hdock-art .hdock.vlane-bar::before,
html.hdock-art .hdock.vlane-bar::after { display: none; }

/* The drawer is the FILM drawn out of the slot, and it is modern stock to
   match the canister: black celluloid, crisp backlit perforations, plain
   glass plaques (Rober: "the opening source is ugly though but i like the
   cylinder" — the painted, scratched amber film was the ugly part). Pure CSS,
   so it is sharp at any pixel density: the perforation is one tiny SVG
   tile repeated along each edge. Its top edge starts just under the
   canister, in the canister's shadow. */
html.hdock-art .hdock.vlane-bar + .media-sources.is-drawer {
  --perf: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='22' height='9'%3E%3Crect x='6' y='1' width='10' height='7' rx='1.6' fill='%23ffffff' fill-opacity='.14'/%3E%3C/svg%3E");
}
html.hdock-art .hdock.vlane-bar + .media-sources.is-drawer {
  --drawer-tuck: 6px;
  --source-brass: 255, 255, 255;
  --source-ink: #eceef2;
  --source-muted: #9aa0aa;
  margin-left: 58px;
  margin-right: 38px;
  padding-top: 28px;
  padding-bottom: 24px;
  border: 1px solid rgba(255, 255, 255, .07);
  border-top: 0;
  border-radius: 0 0 12px 12px;
  background:
    var(--perf) left 10px top 11px / 22px 9px repeat-x,
    var(--perf) left 10px bottom 8px / 22px 9px repeat-x,
    linear-gradient(180deg, rgba(0, 0, 0, .6), transparent 24px),
    linear-gradient(180deg, #131417, #0a0b0d);
  box-shadow: inset 0 -1px 0 rgba(255, 255, 255, .04), 0 16px 26px -16px #000;
}
html.hdock-art .hdock.vlane-bar + .media-sources :is(.media-source-chip, .media-source-nav, .media-sources-icons, .media-sources-expand) {
  border-radius: 10px;
  border-color: rgba(255, 255, 255, .08);
  background: rgba(255, 255, 255, .035);
  box-shadow: none;
}
html.hdock-art .hdock.vlane-bar + .media-sources :is(.media-source-chip, .media-source-nav:not([aria-disabled='true']), .media-sources-icons, .media-sources-expand):hover {
  border-color: rgba(255, 255, 255, .22);
  background: rgba(255, 255, 255, .075);
}
/* Selected: the canister's own amber ring colour. */
html.hdock-art .hdock.vlane-bar + .media-sources :is(.media-source-chip.active, .media-sources-icons[aria-pressed='true']) {
  border-color: rgba(245, 158, 11, .8);
  background: rgba(245, 158, 11, .12);
  box-shadow: inset 0 0 0 1px rgba(245, 158, 11, .22);
}
html.hdock-art .hdock.vlane-bar + .media-sources .media-source-count { border-left-color: rgba(255, 255, 255, .1); }
html.hdock-art .hdock.vlane-bar + .media-sources .media-source-nav > span { font: 300 30px/1 system-ui, sans-serif; margin-top: -3px; }

/* The canister's Sources control is one of its plaques (the :is() rule
   below); filtered, it takes the canister's own amber ring colour. */
html.hdock-art .hdock.vlane-bar .source-pull.is-filtered:not(.is-open) {
  border-color: rgba(245, 158, 11, .8);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .08), 0 0 14px -4px rgba(245, 158, 11, .6);
}

/* The plaques on the canister are SOLID (Rober, 2026-09-29: "text feels a
   bit hard to read"). The lodge plaques are 58% see-through, which is fine on
   dark walnut — on polished gunmetal the bright specular band ran straight
   through them, behind the labels, and the unlit labels were --text-dim grey.
   Here they are near-opaque graphite with bright labels; the lit lane keeps
   its colour, and Favourites keeps its two states, on that solid base. */
html.hdock-art .hdock.vlane-bar :is(.vlane-split, .vlane-btn, .vlane-add, .hdock-btn) {
  border-color: rgba(255, 255, 255, .13);
  background: linear-gradient(180deg, rgba(40, 42, 47, .96), rgba(17, 18, 21, .96));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .08), 0 2px 6px -2px rgba(0, 0, 0, .7);
  color: #eceef2;
  text-shadow: 0 1px 1px rgba(0, 0, 0, .6);
}
html.hdock-art .hdock.vlane-bar :is(.vlane-split, .vlane-btn, .vlane-add, .hdock-btn):hover {
  border-color: rgba(255, 255, 255, .28);
  background: linear-gradient(180deg, rgba(52, 55, 61, .97), rgba(24, 25, 29, .97));
  color: #fff;
}
/* The tray on the canister: the solid graphite the plaques were, so the
   specular band stays out from behind the icons; the segments are clear
   inside it and the hairlines are steel, not brass. */
html.hdock-art .hdock.vlane-bar .hdock-tools::before {
  border-color: rgba(255, 255, 255, .15);
  background: linear-gradient(180deg, rgba(15, 16, 19, .97), rgba(32, 34, 39, .97));
  box-shadow: inset 0 1px 0 rgba(0, 0, 0, .65), inset 0 -1px 0 rgba(255, 255, 255, .06), 0 2px 6px -2px rgba(0, 0, 0, .7);
}
html.hdock-art .hdock.vlane-bar .hdock-tools > .hdock-btn {
  border-color: transparent;
  background: transparent;
  box-shadow: none;
}
html.hdock-art .hdock.vlane-bar .hdock-tools > .hdock-btn:hover {
  border-color: transparent;
  background: linear-gradient(180deg, rgba(64, 67, 74, .97), rgba(42, 44, 49, .97));
}
html.hdock-art .hdock.vlane-bar .hdock-tools > .hdock-btn:not(.hidden, [hidden]) ~ .hdock-btn:not(.hidden, [hidden])::before {
  background: linear-gradient(180deg, transparent, rgba(255, 255, 255, .2) 25%, rgba(255, 255, 255, .2) 75%, transparent);
}
/* The library tray on the canister: the tools tray's graphite and steel, so
   both ends of the shelf are the same hand; its segments are clear inside it. */
html.hdock-art .hdock.vlane-bar .vlane-libs {
  border-color: rgba(255, 255, 255, .15);
  background: linear-gradient(180deg, rgba(15, 16, 19, .97), rgba(32, 34, 39, .97));
  box-shadow: inset 0 1px 0 rgba(0, 0, 0, .65), inset 0 -1px 0 rgba(255, 255, 255, .06), 0 2px 6px -2px rgba(0, 0, 0, .7);
}
html.hdock-art .hdock.vlane-bar .vlane-libs > :is(.vlane-btn:not(.active), .vlane-add) {
  border-color: transparent;
  background: transparent;
  box-shadow: none;
}
html.hdock-art .hdock.vlane-bar .vlane-libs > :is(.vlane-btn:not(.active), .vlane-add):hover {
  border-color: transparent;
  background: linear-gradient(180deg, rgba(64, 67, 74, .97), rgba(42, 44, 49, .97));
}
html.hdock-art .hdock.vlane-bar .vlane-libs > * + *::before {
  background: linear-gradient(180deg, transparent, rgba(255, 255, 255, .2) 25%, rgba(255, 255, 255, .2) 75%, transparent);
}
/* The add control needs the same solid seat over the canister's reflection. */
html.hdock-art .hdock.vlane-bar .vlane-add {
  border-color: rgb(var(--dock-ember));
  color: rgb(var(--dock-ember));
}
html.hdock-art .hdock.vlane-bar .vlane-add:hover {
  border-color: rgb(var(--dock-ember));
  color: #fff;
}
html.hdock-art .hdock.vlane-bar .vlane-btn.active {
  border-color: rgba(var(--lane-rgb), .85);
  background:
    linear-gradient(180deg, rgba(var(--lane-rgb), .3), rgba(var(--lane-rgb), .12)),
    linear-gradient(180deg, rgba(30, 31, 35, .97), rgba(14, 15, 17, .97));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .14), 0 0 14px -4px rgba(var(--lane-rgb), .6);
  color: #fff;
}
html.hdock-art .hdock.vlane-bar .hdock-tools > .hdock-more.is-set {
  border-color: rgba(245, 158, 11, .85);
  background:
    linear-gradient(180deg, rgba(245, 158, 11, .28), rgba(245, 158, 11, .1)),
    linear-gradient(180deg, rgba(30, 31, 35, .97), rgba(14, 15, 17, .97));
}
html.hdock-art .hdock.vlane-bar .hdock-drawer:is(:hover, :focus-within, .is-open) > .hdock-more:not(.is-set) {
  background: linear-gradient(180deg, rgba(64, 67, 74, .97), rgba(42, 44, 49, .97));
}
html.hdock-art .hdock.vlane-bar .hdock-fav[data-state='only'] {
  border-color: rgba(245, 158, 11, .85);
  background:
    linear-gradient(180deg, rgba(245, 158, 11, .28), rgba(245, 158, 11, .1)),
    linear-gradient(180deg, rgba(30, 31, 35, .97), rgba(14, 15, 17, .97));
  color: #fde7c0;
}
html.hdock-art .hdock.vlane-bar .hdock-fav[data-state='hide'] {
  border-color: rgba(148, 163, 184, .6);
  background:
    linear-gradient(180deg, rgba(148, 163, 184, .2), rgba(71, 85, 105, .1)),
    linear-gradient(180deg, rgba(30, 31, 35, .97), rgba(14, 15, 17, .97));
  color: #e2e8f0;
}
html.hdock-art .hdock.vlane-bar .hdock-btn-lbl,
html.hdock-art .hdock.vlane-bar .vlane-btn span { color: inherit; }

/* ── The shelf OPENS (2026-10-10) ──
   Rober: "a sort of centered closed tin with like the top and bottom parts and
   then it scrolls open in both directions horizontally" — and, of the Videos
   canister, "decent can you do the other shelves?". Entering a tab, the dock's
   two painted ends stand pressed together in the middle — a short shut thing
   — and slide apart to the dock's two edges while what is between them is
   uncovered: the pills, and the plate's own middle. One value does it all:
   --can-o is 0 shut and 1 open, set each frame by dock.js openPlate(), and
   every edge below is a function of it, so the last frame is pixel for pixel
   the resting plate and the hand-over is invisible.

   Each plate sets four numbers on its host and paints its own children
   (.hdock-open-body / -l / -r, made by dock.js, data-plate names the plate):
     --can-l-w / --can-r-w   how far each end's OUTER edge stands from the
                             centre when shut (its width, for a cap)
     --can-in-l / --can-in-r the end's opaque depth: where the pills start to
                             show, measured from that outer edge (defaults to
                             the width — the whole cap covers them; 0 for a
                             plate whose end is only a rounded corner)
     --can-pad-l / --can-pad-r  the host's border + padding on each side, so
                             the rail's clip can be worked out in the rail's
                             own box (percentages in clip-path are its own)
   The shared block clips the rail and the chips to the stretch between the
   ends' inner edges and fades them in over the second half, so a pill never
   shows through a transparent corner as an end passes. The rail sits inside
   the host's padding, so the dock's centre is 50% of the rail plus half the
   two paddings, and an inner edge is the outer edge plus the opaque depth,
   less the padding on that side. Reduced motion never starts it (dock.js). */
.hdock.is-opening {
  --can-o: 0;
  --can-shut: calc(1 - var(--can-o));
}
.hdock.is-opening > .hdock-open {
  position: absolute;
  top: 0;
  bottom: 0;
  pointer-events: none;
}
.hdock.is-opening > :is(.hdock-rail, .hdock-chips) {
  position: relative;
  z-index: 1;
  opacity: clamp(0, (var(--can-o) - .4) / .6, 1);
  clip-path: inset(
    0
    calc((50% + (var(--can-pad-l) + var(--can-pad-r)) / 2 - var(--can-r-w)) * var(--can-shut) + var(--can-in-r, var(--can-r-w)) - var(--can-pad-r))
    0
    calc((50% + (var(--can-pad-l) + var(--can-pad-r)) / 2 - var(--can-l-w)) * var(--can-shut) + var(--can-in-l, var(--can-l-w)) - var(--can-pad-l))
  );
}

/* The canister. H is the dock's own height (--dock-h-px); the caps are drawn
   at that height, so their widths are the art's ratios of it (108/252,
   86/252). While it opens the host paints nothing itself: the body and the
   two ends are three children, each with the plate's own shadow, and the
   host's clip-path is the tin's outline, so nothing shows outside the ends.
   The last frame is the resting plate above (caps at the edges, body .37H to
   .30H in). A dock narrower than the phone breakpoint is the film strip, not
   the canister, and never opens (dock.js). */
html.hdock-art .hdock.vlane-bar.is-opening {
  --can-pad-l: 58px;
  --can-pad-r: 48px;
  --can-l-w: calc(var(--dock-h-px) * .4286);
  --can-r-w: calc(var(--dock-h-px) * .3413);
  /* the ends' outer edges: where each cap's picture starts and ends */
  --can-edge-l: calc((50% - var(--can-l-w)) * var(--can-shut));
  --can-edge-r: calc((50% - var(--can-r-w)) * var(--can-shut));
  background: none;
  filter: none;
  clip-path: inset(0 var(--can-edge-r) 0 var(--can-edge-l));
}
html.hdock-art .hdock.vlane-bar.is-opening > .hdock-open {
  filter: drop-shadow(0 8px 10px rgba(0, 0, 0, .55));
}
/* The body: the plate's own stretch, clipped to the span between the ends. */
html.hdock-art .hdock.vlane-bar.is-opening > .hdock-open-body {
  left: 0;
  right: 0;
  z-index: 0;
  background: url('dock/can-body.webp') calc(var(--dock-h-px) * .37) center / calc(100% - var(--dock-h-px) * .67) 100% no-repeat;
  clip-path: inset(0 calc(var(--can-edge-r) + var(--dock-h-px) * .30) 0 calc(var(--can-edge-l) + var(--dock-h-px) * .37));
}
/* The two ends: each lives in its half of the dock, picture against the
   middle, and slides out to its edge (100% here is the half's own width). */
html.hdock-art .hdock.vlane-bar.is-opening > .hdock-open-l,
html.hdock-art .hdock.vlane-bar.is-opening > .hdock-open-r { z-index: 2; }
html.hdock-art .hdock.vlane-bar.is-opening > .hdock-open-l {
  left: 0;
  right: 50%;
  background: url('dock/can-l.webp') right center / auto 100% no-repeat;
  transform: translateX(calc((-100% + var(--can-l-w)) * var(--can-o)));
}
html.hdock-art .hdock.vlane-bar.is-opening > .hdock-open-r {
  left: 50%;
  right: 0;
  background: url('dock/can-r.webp') left center / auto 100% no-repeat;
  transform: translateX(calc((100% - var(--can-r-w)) * var(--can-o)));
}

/* The walnut mantel (Games, Images): the plate is a 9-slice of frame.webp,
   so its ends are the two carved brass caps at the border's width (34px) and
   its middle the wood between. Shut, the caps stand pressed together as a
   closed clasp; open, they are the host's own border. The children are cut
   with the SAME border-image — a cap is a 34px element wearing only the
   left (or right) border, the body wears only the top and bottom — so the
   last frame is the resting 9-slice to the pixel. The host keeps its border
   WIDTH (the rail must not move), only the picture leaves it. A child is
   placed against the padding box, hence the negative insets that reach the
   border box; 50% here is the padding box, whose centre is the plate's.
   The wood is uncovered, not stretched: the body spans the whole plate under
   a clip that opens with the ends, so the grain holds still. The shut clasp
   casts a shadow the resting plate does not have, so it fades with --can-o
   and is gone at the hand-over. */
html.hdock-art .hdock.is-opening[data-plate='mantel'] {
  --can-pad-l: 46px;   /* border 34 + padding 12 */
  --can-pad-r: 46px;
  --can-l-w: 34px;
  --can-r-w: 34px;
  border-image: none;
  border-color: transparent;
}
html.hdock-art .hdock.is-opening[data-plate='mantel'] > .hdock-open {
  top: calc(-1 * var(--dock-band-t));
  bottom: calc(-1 * var(--dock-band-b));
  box-sizing: border-box;
  border-style: solid;
  border-image: url('dock/frame.webp') 26 95 30 95 fill stretch;
  filter: drop-shadow(0 6px 8px rgba(0, 0, 0, calc(.5 * var(--can-shut))));
}
html.hdock-art .hdock.is-opening[data-plate='mantel'] > .hdock-open-body {
  left: 0;
  right: 0;
  z-index: 0;
  border-width: var(--dock-band-t) 0 var(--dock-band-b);
  clip-path: inset(0 calc(50% * var(--can-shut)) 0 calc(50% * var(--can-shut)));
}
html.hdock-art .hdock.is-opening[data-plate='mantel'] > .hdock-open-l,
html.hdock-art .hdock.is-opening[data-plate='mantel'] > .hdock-open-r {
  z-index: 2;
  width: var(--dock-band-x);
}
html.hdock-art .hdock.is-opening[data-plate='mantel'] > .hdock-open-l {
  left: calc(50% * var(--can-shut) - var(--dock-band-x));
  border-width: var(--dock-band-t) 0 var(--dock-band-b) var(--dock-band-x);
}
html.hdock-art .hdock.is-opening[data-plate='mantel'] > .hdock-open-r {
  right: calc(50% * var(--can-shut) - var(--dock-band-x));
  border-width: var(--dock-band-t) var(--dock-band-x) var(--dock-band-b) 0;
}
@media (max-width: 560px) {
  html.hdock-art .hdock.is-opening[data-plate='mantel'] { --can-pad-l: 42px; --can-pad-r: 42px; }
}

/* Narrow: the dock wraps to two or three rows, and a canister that tall has
   caps wide enough to sit on the pills. So below 700px the dock is the same
   black film as the drawer, perforations top and bottom, and the drawer
   under it reads as more of the same strip. */
@media (max-width: 700px) {
  html.hdock-art .hdock.vlane-bar {
    --perf: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='22' height='9'%3E%3Crect x='6' y='1' width='10' height='7' rx='1.6' fill='%23ffffff' fill-opacity='.14'/%3E%3C/svg%3E");
    min-height: 0;
    padding: 24px 10px;
    border: 1px solid rgba(255, 255, 255, .08);
    border-radius: 12px;
    background:
      var(--perf) left 8px top 8px / 22px 9px repeat-x,
      var(--perf) left 8px bottom 8px / 22px 9px repeat-x,
      linear-gradient(180deg, #17181b, #0b0c0e);
    filter: none;
  }
  html.hdock-art .hdock.vlane-bar + .media-sources.is-drawer { margin-left: 10px; margin-right: 10px; }
}

/* The search bar on the canister: the tools tray's graphite and steel, so the
   field and the tray beside it are the same hand. */
html.hdock-art .hdock.vlane-bar .hdock-find {
  border-color: rgba(255, 255, 255, .15);
  background: linear-gradient(180deg, rgba(15, 16, 19, .97), rgba(32, 34, 39, .97));
  box-shadow: inset 0 1px 0 rgba(0, 0, 0, .65), inset 0 -1px 0 rgba(255, 255, 255, .06), 0 2px 6px -2px rgba(0, 0, 0, .7);
}
html.hdock-art .hdock.vlane-bar .hdock-find:hover { border-color: rgba(255, 255, 255, .26); }
html.hdock-art .hdock.vlane-bar .hdock-find:focus-within {
  border-color: rgba(var(--dock-lane), .8);
  box-shadow: inset 0 1px 0 rgba(0, 0, 0, .65), 0 0 0 3px rgba(var(--dock-lane), .18), 0 0 18px -6px rgba(var(--dock-lane), .6);
}
html.hdock-art .hdock.vlane-bar .hdock-find-k kbd { border-color: rgba(255, 255, 255, .2); background: linear-gradient(180deg, rgba(64, 67, 74, .9), rgba(30, 31, 35, .95)); }
