@layer components {
  /* Mirrors .sidebar__toggle: lives at the end of the page nav; when the dock
     opens it leaves the nav's flex flow and anchors to the dock's top corner.
     The fixed header is the containing block (backdrop-filter), so the
     negative end inset lands 1ch inside the viewport edge — and because the
     header's inline insets animate with the same curve as the dock slide, the
     keycap rides the dock's corner through both transitions. */
  .dock__toggle {
    transition:
      inset-inline-end 0.2s ease-out,
      color 0.2s ease-out;
    z-index: 1;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 0.5ch;
    color: var(--color-ink);

    input[type="checkbox"] {
      display: none;
    }

    :has(#dock-toggle:checked) & {
      color: var(--color-red);

      @media (min-width: 70ch) {
        position: absolute;
        /* Centre on the header bar: half the slack between the bar and the
           keycap (1.4em at the keycap font). */
        inset-block-start: calc((var(--header-height) - 1.4 * clamp(1rem, 2.5vi, 1.4rem)) / 2);
        inset-inline-end: calc(var(--inline-space) - var(--dock-width));
      }
    }

    @media (max-width: 70ch) {
      display: none;
    }
  }

  /* The toggles read as a quiet panel icon; the letter beside it — revealed by
     Shift — is a miniature of the house keycap (base.css kbd): currentColor
     border plus the 0.1em bottom-edge shadow, so it tints muted at rest, ink
     on hover and dock-red when open, all through inheritance. The outer kbd is
     just the layout capsule. */
  :is(.sidebar__toggle, .dock__toggle, .dock__wide-toggle, .dock__full-toggle, .palette__toggle, .timeline__toggle, .help__toggle, .avatar-menu__trigger) kbd {
    /* Center, not baseline: the mini keycap is a bordered box beside a larger
       icon, so it should sit on the icon's optical middle. */
    align-items: center;
    border: 0;
    box-shadow: none;
    color: var(--color-ink-muted);
    display: inline-flex;
    /* --font-medium-responsive, but viewport-relative: the cqi-based var
       would shrink inside #dock (a size container), leaving the wide
       toggle's keycap smaller than the header ones. */
    font-size: clamp(1rem, 2.5vi, 1.4rem);
    gap: 0.3ch;
    line-height: 1;
    opacity: 1;
    /* Tight inline padding: the reserved (invisible) keycaps already space the
       toggles apart; generous padding on top read as gaps in the header. */
    padding: 0.2em 0.25em;
    transition: color 0.15s ease;
  }

  /* The timeline clock and help mark are link-blue actions; only the
     revealed keycap letter rides the kbd's muted-to-ink ride. */
  :is(.timeline__toggle, .help__toggle) kbd i {
    color: var(--color-blue);
    transition: color 150ms ease;
  }

  :is(.timeline__toggle, .help__toggle):hover kbd i {
    color: var(--color-blue-bright);
  }

  .timeline__toggle {
    align-items: center;
    display: inline-flex;
  }

  /* Basecamp-style hint reveal: every shortcut fires with Shift, and holding
     Shift is also what shows the letters — hotkey-mode flips one attribute on
     <body>, CSS does all the showing. No letters on touch or narrow screens,
     where there is no Shift to hold. */
  .key-letter {
    display: none;
    border: 1px solid currentColor;
    border-radius: 0.3em;
    box-shadow: 0 0.1em 0 currentColor;
    /* Rides the kbd font so the cap shrinks with its icon on smaller screens;
       floored at legibility. ~0.65rem beside the full-size header icons. */
    font-size: max(0.55rem, 0.46em);
    font-weight: 600;
    line-height: 1;
    padding: 0.15em 0.4em;
    /* Optical: the solid bottom-edge shadow adds visual mass below the
       flex-centred box, so the cap reads low — lift it by half the shadow. */
    translate: 0 -0.05em;
  }

  /* Underlined hosts (.link triggers) draw their text-decoration straight
     through blockified flex children, and the child cannot cancel a propagated
     decoration — but propagation skips the contents of atomic inlines, so the
     letter lives in an inner span (rendered by the key_letter helper). */
  .key-letter > span {
    display: inline-block;
  }

  /* The avatar's U keycap has no icon inside — hide the whole capsule, or its
     empty padding box would linger beside the avatar. */
  .avatar-menu__trigger kbd {
    display: none;
  }

  /* Shift toggles the keycaps into the flow wherever a keyboard is likely
     (hover-capable screens, any width) — the bars may reflow; only the
     absolutely-centred breadcrumbs are guaranteed still. Touch devices never
     see the caps. */
  @media (any-hover: hover) {
    /* :where keeps the reveal's specificity below composite hiders like
       .btn--collapse's icon-only state, which must win while collapsed. */
    body[data-hotkey-mode] :where(.key-letter) {
      display: inline-block;
    }

    body[data-hotkey-mode] .avatar-menu__trigger kbd {
      display: inline-flex;
    }
  }

  :is(.sidebar__toggle, .dock__toggle, .dock__wide-toggle, .dock__full-toggle, .palette__toggle, .timeline__toggle, .help__toggle, .avatar-menu__trigger):is(:hover, :has(input:checked)) kbd,
  .dock__full-toggle--active kbd {
    color: inherit;
  }

  /* The resize + fullscreen keycaps sit at the dock's inner (left) edge —
     widening pulls that edge outward. One positioned flex row holds both so they
     share the header's line; the controls inside are static. */
  .dock__controls {
    align-items: center;
    display: inline-flex;
    gap: 0.5ch;
    /* Same centring as the main J toggle, so both rows share the header's
       vertical middle. */
    inset-block-start: calc((var(--header-height) - 1.4 * clamp(1rem, 2.5vi, 1.4rem)) / 2);
    inset-inline-start: var(--inline-space);
    position: absolute;
    /* Above the dock content, whose nav box transparently overlaps this corner
       and would swallow hover and clicks. */
    z-index: 1;
    /* Match the main J toggle's keycap height (main font 1.4rem max × line-height
       1 + 0.4em padding = 1.4em) so the smaller secondary keycaps centre on the
       same axis as the main toggle instead of top-aligning a couple px higher. */
    min-block-size: calc(1.4 * clamp(1rem, 2.5vi, 1.4rem));
  }

  .dock__wide-toggle,
  .dock__full-toggle {
    align-items: center;
    color: var(--color-ink);
    cursor: pointer;
    display: inline-flex;

    input[type="checkbox"] {
      display: none;
    }
  }

  /* These are secondary controls beside the main J toggle — a notch smaller so
     the dock toggle stays the primary mark. Padding/gap are em-based, so scaling
     the font shrinks the whole keycap proportionally. */
  .dock__controls kbd {
    font-size: clamp(0.85rem, 2.1vi, 1.2rem);
  }

  /* The fullscreen control is a real <button> (so the controller can hide it
     where the API is unsupported); strip the button chrome to match the label. */
  .dock__full-toggle {
    background: none;
    border: 0;
    font: inherit;
    padding: 0;
  }

  .dock__controls:has(#dock-wide:checked) .dock__wide-toggle,
  .dock__full-toggle--active {
    color: var(--color-red);
  }

  body.app:has(#dock-wide:checked) {
    --dock-width: 45vw;
  }

  /* The dock is a size container, so .btn--collapse — which keys off the
     viewport — never collapses inside a narrow dock on a wide screen. Mirror the
     collapse against the dock's own inline size so labelled actions (e.g. Neues
     Handbuch) shrink to their icon here too. */
  @container (max-width: 30rem) {
    #dock .btn--collapse {
      --btn-padding: 0;
      --btn-collapse-size: calc(1lh + 2 * var(--space-xxxs) + 4px);

      display: inline-grid;
      place-items: center;
      inline-size: var(--btn-collapse-size);
      block-size: var(--btn-collapse-size);
    }

    #dock .btn--collapse > :not(i):not(.for-screen-reader) {
      display: none;
    }
  }

  /* The dock is a utility surface: reading columns open up to the panel edge
     (the panel width is the measure) and prose drops a notch under the app's
     primary size. The full handbook page keeps the website reading treatment. */
  #dock .content-width-reading {
    inline-size: 100%;
  }

  #dock .prose {
    font-size: var(--font-small-responsive);
  }

  /* Tenant rail: the dock is a small stack of coexisting surfaces, each in its
     own permanent frame, so switching tenants never loses state. Hidden while
     only the resident tenant exists — it appears once a preview lands in the
     ephemeral slot. */
  .dock__rail {
    align-items: center;
    display: flex;
    gap: var(--inline-space);
    margin-block-end: var(--block-space);
  }

  #dock:has(#dock_preview:empty) .dock__rail {
    display: none;
  }

  .dock__tab {
    align-items: center;
    color: var(--color-ink-muted);
    cursor: pointer;
    display: inline-flex;
    font-size: var(--font-small-responsive);
    gap: 0.5ch;

    input[type="radio"] {
      display: none;
    }

    &:hover,
    &:has(input:checked) {
      color: var(--color-ink);
    }

    &:has(input:checked) {
      font-weight: 500;
      text-decoration: underline;
      text-decoration-thickness: 0.15em;
      text-underline-offset: 0.5em;
    }
  }

  .dock__tab-group {
    align-items: center;
    display: inline-flex;
    gap: 0.5ch;
  }

  .dock__tab-close {
    background: none;
    border: 0;
    color: var(--color-ink-muted);
    cursor: pointer;
    padding: 0;

    &:hover {
      color: var(--color-ink);
    }
  }

  /* The checked radio picks the visible frame. The empty slot never wins:
     while a preview is still loading, handbooks stays up and the swap happens
     only when content lands — no blank flash. */
  #dock:has(#dock-tenant-preview:checked):not(:has(#dock_preview:empty)) #dock_content {
    display: none;
  }

  #dock:has(#dock-tenant-handbooks:checked) #dock_preview,
  #dock_preview:empty {
    display: none;
  }

  /* No sticky header overlaps the dock's own scroller — anchored headings only
     need a breath of headroom here, not the full-page header clearance. */
  #dock .prose :is(h1, h2, h3)[id] {
    scroll-margin-block-start: var(--block-space);
  }

  /* Native Fullscreen API lifts #dock to the browser's top layer at 100vw — the
     grid, header and sidebar are untouched (they're simply not painted). This
     block is purely cosmetic: the header-clearing offsets no longer apply (no
     header), and the reading column re-centers so a handbook doesn't run
     edge-to-edge. Zero interaction with --dock-width or the grid. */
  #dock:fullscreen {
    margin-block-start: 0;
    /* Clear the absolutely-positioned ⇧F keycap (its inset + height ≈ 2.2rem) so
       the first line of content isn't tucked under it. */
    padding-block-start: var(--block-space-double);

    /* Widening is meaningless in fullscreen (no grid to widen into) — leave only
       the ⇧F exit control. */
    .dock__wide-toggle {
      display: none;
    }

    .content-width-reading {
      inline-size: min(clamp(38.3rem, 95.8cqi, 53.65rem), 100%);
      margin-inline: auto;
    }

    .prose {
      font-size: clamp(1rem, 2.5cqi, 1.4rem);
    }
  }


  /* Search input sits IN the dock's grey ground instead of popping as a bright
     white card. A hair lighter than the ground reads as a gently recessed field;
     the whole group shares one fill so the icon side no longer looks bolted on.
     Derived from the ground colour, so it tracks light/dark automatically. */
  #dock .input-group {
    background-color: color-mix(in oklch, var(--color-gray-light), var(--color-bg) 55%);
    border-color: color-mix(in oklch, var(--color-ink) 10%, transparent);
  }

  #dock .input-group .form__input,
  #dock .input-group__append {
    background-color: transparent;
  }
}
