/* tray.css — the tab at the bottom of every page and the panel it opens.
 *
 * ITS OWN FILE BECAUSE IT IS ON EVERY PAGE AND THE SITE HAS TWO REGISTERS.
 * The splash is styled by slate.css and everything else by document.css, and
 * the tray belongs to neither: it is site furniture, like the header. Loaded
 * separately it exists once, and a change to it cannot land on one register and
 * not the other, which is the drift the header spent two sessions recovering
 * from.
 *
 * FONT TOKENS ARE ASKED FOR TWICE ON PURPOSE. The two stylesheets name the same
 * two faces differently: --doc-face/--doc-data in one, --face/--data in the
 * other. var(--doc-data, var(--data)) resolves to whichever is defined on the
 * page it lands on, so this file needs no knowledge of which register it is in
 * and neither register needs to know about it. Colours need no such trick:
 * --ink, --paper, --ink-3 and --gutter are named the same in both.
 */

/* ── the tray ─────────────────────────────────────────────────────────────
   A tab at the bottom of the screen that pulls a dark panel up over the page:
   the legal and colophon pages, which have to be reachable from everywhere and
   are not worth a nav item on any of them.

   IT NEEDS NO MEASURED HEIGHT, and that is the whole reason it is built this
   way. The obvious build is a fixed panel translated down by its own height
   with the tab positioned above it, and the tab then needs to know that height
   in pixels, which means JavaScript measuring and a custom property to keep in
   step on every resize and every font change.

   Instead the tab and the panel sit in ONE sliding box and move together.
   .tray-slide is as tall as the panel and sits at the bottom of the viewport.
   translateY(100%) pushes it down by exactly its own height, so the panel
   leaves the screen and the tab, which is pinned to the slide's TOP edge at
   bottom: 100%, lands exactly on the bottom of the viewport. Sliding back to 0
   brings the panel up and the tab rides on top of it. Percentages resolve
   against the element itself, so nothing has to be told a number.

   THE STATIC VERSION IS THE DEFAULT, NOT THE FALLBACK. Everything above is
   inside :root[data-js]. With no script the tray is an ordinary block above the
   footer and every link still works, which matters because these are the terms
   and the privacy notice. data-js is set by the pre-paint head script, so the
   static form is never seen for a frame on a page that will enhance. */

.tray { --tray-gutter: clamp(0.75rem, 3vw, 2.5rem); --tray-r: 0.875rem; }

/* the static form: a plain block of links, no positioning, no animation */
.tray-panel {
  background: var(--ink); color: var(--paper);
  border-radius: var(--tray-r) var(--tray-r) 0 0;
  padding: clamp(1.75rem, 5vh, 3rem) clamp(1.5rem, 5vw, 4rem) clamp(2rem, 6vh, 3.5rem);
  display: flex; flex-direction: column; gap: clamp(1.25rem, 3vh, 2.25rem);
}

/* COLUMNS, AND EACH GROUP READS DOWN. Six legal documents and three colophon
   pages in one wrapping row read as nine unrelated links; stacked, the two
   groups are visibly two groups without a heading or a rule to say so.

   auto-fit rather than a fixed two columns: below about 30rem the two would be
   squeezed into a pair of narrow strips, and this lets them fall into one
   column instead, which is what a phone should get. */
/* FLEX, NOT A GRID OF MINIMUMS. Three of the four columns hold one item, and a
   grid track with a 10rem floor made "About" occupy the same width as six legal
   documents. Flex items size to their own content, so a one-item column is one
   item wide and the gap does the separating. Wrapping is the phone case: the
   columns fall onto the next line rather than being squeezed. */
.tray-cols {
  display: flex; flex-wrap: wrap;
  gap: clamp(1.25rem, 3vh, 1.75rem) clamp(1.5rem, 3.5vw, 3rem);
}

.tray-list {
  display: flex; flex-direction: column; gap: 0.125rem;
  margin: 0; padding: 0; list-style: none;
}

.tray-list a {
  display: block;
  font-family: var(--doc-data, var(--data)); font-size: 0.8125rem; letter-spacing: -0.011em;
  /* Tighter than the body's 1.55. These are a list of addresses read down a
     column, not prose read across a line, and prose leading spreads six of them
     over more height than the panel wants to be. */
  line-height: 1.35;
  color: #a9a9a4; text-decoration: none; white-space: nowrap;
  transition: color 160ms ease;
}

.tray-list a:hover, .tray-list a:focus-visible { color: var(--paper); }

/* CURRENT PAGE IS NAMED, NOT DECORATED. The panel is a list of nine addresses
   with nothing else to tell them apart, so the one you are already on says so
   to a screen reader and reads brighter to everyone else. */
.tray-list a[aria-current="page"] { color: var(--paper); }

/* The colophon, at the foot of the panel. The year is written by
   document.js rather than typed, so it cannot go stale the way the old site's
   "© tradekraft 2024" did. The 2026 in the markup is what shows before the
   script runs and with the script off, which is why it is a real year and not
   an empty span. */
.tray-foot {
  margin: clamp(1.5rem, 4vh, 2.5rem) 0 0;
  font-family: var(--doc-data, var(--data)); font-size: 0.6875rem;
  letter-spacing: 0.06em; color: var(--ink-3);
}

.tray-tab {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 2.5rem; padding: 0 1.5rem;
  border: none; cursor: pointer;
  background: var(--ink); color: var(--paper);
  border-radius: var(--tray-r) var(--tray-r) 0 0;
  font-family: var(--doc-face, var(--face)); font-size: 0.9375rem; font-weight: 500;
  letter-spacing: -0.011em; line-height: 1;
}

/* ── enhanced ─────────────────────────────────────────────────────────── */

:root[data-js] .tray {
  position: fixed; left: 0; right: 0; bottom: 0;
  height: 0; z-index: 70;
}

:root[data-js] .tray-slide {
  position: absolute; left: 0; right: 0; bottom: 0;
  transform: translateY(100%);
  transition: transform 460ms cubic-bezier(0.22, 0.8, 0.2, 1);
}

:root[data-tray="open"] .tray-slide { transform: translateY(0); }

:root[data-js] .tray-panel { margin: 0 var(--tray-gutter); }

:root[data-js] .tray-tab {
  position: absolute; bottom: 100%;
  right: calc(var(--tray-gutter) + clamp(0.5rem, 2vw, 2rem));
}

/* The panel can outgrow a short screen once there are nine links and a phone in
   landscape. Capping it and letting it scroll is the difference between a tray
   and a thing that covers the page it is supposed to be attached to. */
:root[data-js] .tray-panel { max-height: 70svh; overflow-y: auto; }

/* THE LAST SCREEN BELONGS TO WHATEVER IS LAST IN THE FLOW. With a script the
   tray is fixed and out of the flow, so the last section runs to the end of the
   document and its own snap range reaches the bottom. Without one the tray is
   an ordinary block sitting after it, and under mandatory snapping a trailing
   block with no snap position of its own cannot be scrolled to. This is the
   rule the page footer used to carry, moved to what replaced it. */
:root:not([data-js]) .tray { scroll-snap-align: end; }

@media (prefers-reduced-motion: reduce) {
  :root[data-js] .tray-slide { transition: none; }
}
