/* ══ THE PANEL ══════════════════════════════════════════════  7 Sep 2026 ══
   Sir: use the same style of panel as the dashboard, without the display
   picture, with the correct tabs, and do not duplicate tabs or settings the
   dashboard already has.

   THE PANEL WAS ONE PAGE'S, AND IT IS A COMPONENT. Everything below was
   settled on the dashboard across four passes: the wall that travels inside an
   invisible track, the photograph duotoned into navy behind the tabs, the
   single cream pill that travels between rows rather than five backgrounds
   toggling, and the autohiding drawer with four ways out. A second page
   wanting the same panel is the moment it stops being that page's CSS.

   WRITTEN FROM THE MEASUREMENT, NOT MOVED. The dashboard's rules for this are
   spread over five places in a fifteen thousand line file and supersede each
   other in three of them: the wall is declared sticky at one offset and again
   at another, the scrollbar is given a colour and then taken away entirely,
   the panel is given a shadow as a wall and has it removed as a track. Copying
   the source would have carried every losing declaration. Every value here is
   what the shipped panel COMPUTES at 1400, read off the rendered element, and
   the two panels are then diffed element by element.

   WHAT THIS SHEET DOES NOT OWN: what goes IN the panel. Identity, a set of
   tabs and a way out is the shape; which tabs, and whether there is a ledger
   or a search under them, is the page's decision. A component that fills
   itself can only be used once.

   TOKENS ONLY. Every colour resolves to a variable the loading page declares.
   ═════════════════════════════════════════════════════════════════════════ */

/* ---- THE SHELL ---------------------------------------------------------- */
.dash-shell {
  display: grid;
  grid-template-columns: 258px minmax(0, 1fr);
  gap: clamp(14px, 1.6vw, 24px);
  align-items: start;
}
.dash-body { min-width: 0; }

/* ---- THE TRACK, AND THE WALL THAT STANDS IN IT --------------------------
   Two objects, and painting the wrong one is the mistake this pair invites.
   `.dash-rail` is an invisible TRACK: no ground, no pointer, spanning the
   shell so the sticky thing inside it has somewhere to go and somewhere to
   stop. `.rail-in` is the WALL: navy, its own height, sticky under the
   masthead, landing on the footer when the track runs out.

   Painted the other way round the ground stands still from the masthead to the
   footer while the contents slide up out of it, and the eye reads the half
   that does not move. */
.dash-rail {
  position: static; height: auto; align-self: stretch;
  display: block; padding: 0; gap: 0;
  max-height: none; overflow: visible; background: none;
}
.rail-in {
  position: sticky;
  top: calc(74px + clamp(14px, 1.6vw, 24px));
  max-height: calc(100vh - 74px - clamp(28px, 3.2vw, 48px));
  overflow-y: auto; overscroll-behavior: contain;
  display: flex; flex-direction: column; gap: 20px;
  padding: 26px var(--edge);
  background: var(--navy); color: var(--cream);
  box-sizing: border-box;
}
/* The panel still scrolls and still keeps the wheel; it stops drawing a bar
   down a navy field with nothing else vertical in it. */
.rail-in { scrollbar-width: none; }
.rail-in::-webkit-scrollbar { width: 0; height: 0; display: none; }
.rail-in::-webkit-scrollbar-thumb,
.rail-in::-webkit-scrollbar-track { background: none; }

/* ---- WHO IT IS ---------------------------------------------------------- */
.rail-id { padding: 0 0 16px; text-align: center; }
.rail-name {
  margin: 0; font-family: var(--sans); font-size: 13px; font-weight: 500;
  letter-spacing: .16em; text-transform: uppercase; color: var(--cream);
  line-height: 1.15;
}
.rail-role {
  margin: 6px 0 0; font-family: var(--serif); font-size: 12.5px;
  line-height: 1.4; color: rgba(250, 248, 243, .55);
}

/* ---- THE STACK, AND THE GROUND BEHIND IT --------------------------------
   Everything from the first tab to the foot sits in the stack, and the picture
   is absolutely positioned behind all of it. The stack takes the leftover
   height, so the picture reaches the bottom of the panel at any viewport with
   no number written down anywhere. */
.rail-stack {
  position: relative; flex: 1 1 auto;
  display: flex; flex-direction: column; gap: 20px;
  margin: 0 calc(-1 * var(--edge)) -26px;
  padding: 0 var(--edge) 26px;
}
/* DUOTONED INTO NAVY IN THE FILE, which is the only reason cream survives on
   it: the whole picture lives between two navies, so the building reads as an
   outline and a set of tonal shifts rather than as a photograph competing with
   the words on top of it.

   THE EMBOSS IS BAKED, NOT FILTERED, and the panel carries the other half: a
   cream hairline where the slab begins and a dark one under it.

   BOTH ENDS DISSOLVE, FOR DIFFERENT REASONS. The top so the edge is a light
   line on a deepening sky rather than a cut through a photograph. The foot so
   the picture ARRIVES at the footer instead of stopping on it: both grounds
   are the same navy, so nothing needs recolouring, the picture simply has to
   have got there. */
.rail-night {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: url('hyyryn-night.jpg') center bottom / cover no-repeat;
  opacity: .92;
  box-shadow: inset 0 1px 0 rgba(250, 248, 243, .14),
              inset 0 2px 0 rgba(4, 9, 15, .55),
              inset 0 -1px 0 rgba(4, 9, 15, .5);
  -webkit-mask-image: linear-gradient(to bottom, rgba(0,0,0,.55) 0%, black 7%,
                      black 84%, rgba(0,0,0,.5) 94%, transparent 100%);
          mask-image: linear-gradient(to bottom, rgba(0,0,0,.55) 0%, black 7%,
                      black 84%, rgba(0,0,0,.5) 94%, transparent 100%);
}

/* ---- THE TABS ----------------------------------------------------------- */
.rail-nav {
  position: relative; z-index: 1;
  display: flex; flex-direction: column; gap: 2px;
}
.rail-nav .dash-tab-btn {
  position: relative; z-index: 1;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; flex: 0 0 auto;
  padding: 11px 18px; border: 0; border-radius: 999px;
  background: none; cursor: pointer; text-align: left; text-decoration: none;
  font-family: var(--sans); font-size: 10.5px; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase;
  color: rgba(250, 248, 243, .72);
  /* EVERY ROW IS THE HEIGHT OF A ROW WITH A COUNT. The one tab with no number
     beside it has a 12px line box against a count chip's 18, so it stood 34
     tall against everyone else's 40. Nothing showed it while the highlight was
     a background appearing and disappearing; a pill that travels between them
     changes size on the way and those six pixels become the most obvious thing
     in the panel. */
  line-height: 18px;
  transition: color .22s ease, background .2s ease;
}
.rail-nav .dash-tab-btn:hover { color: var(--cream); background: rgba(250, 248, 243, .08); }
.rail-nav .dash-tab-btn.active { background: var(--cream); color: var(--navy); }
.rail-nav .dash-tab-btn:focus-visible { outline: 2px solid var(--cream); outline-offset: -2px; }
.rail-nav .tab-count {
  display: flex; align-items: center; justify-content: center;
  font-family: var(--sans); font-size: 10.5px; font-weight: 600;
  letter-spacing: .06em; line-height: 1;
  color: rgba(250, 248, 243, .55); font-variant-numeric: tabular-nums;
}
.rail-nav .dash-tab-btn.active .tab-count { color: var(--muted); }

/* ---- ONE HIGHLIGHT THAT TRAVELS -----------------------------------------
   It was backgrounds switching on and off, which blinks from one row to
   another with nothing in between. One cream pill is measured against
   whichever row the pointer or the keyboard is on and translated to it, so the
   eye is carried from the row it left to the row it arrived at.

   THE TEXT FOLLOWS THE PILL, NOT THE SELECTION. Otherwise hovering row three
   slides the cream out from under row one and leaves navy on navy. `.is-lit`
   is set by the same code that moves the pill, so exactly one row is ever
   dark-on-cream and it is always the row the pill is under.

   AND IT IS ALL SCOPED TO `.has-ink`, a class the script sets when it mounts
   the pill. Without the guard a reader with no JavaScript gets the worst of
   both: these rules take the cream off the live row and nothing puts one back.
   With it, no JavaScript means the panel as it was. */
.rail-ink {
  position: absolute; left: 0; top: 0; z-index: 0; pointer-events: none;
  width: 0; height: 0; border-radius: 999px; background: var(--cream);
  box-shadow: 0 1px 0 rgba(250, 248, 243, .20),
              0 8px 16px -10px rgba(4, 9, 15, .95);
  transition: transform 300ms cubic-bezier(.16, 1, .3, 1),
              width 300ms cubic-bezier(.16, 1, .3, 1),
              height 300ms cubic-bezier(.16, 1, .3, 1);
}
.rail-nav.has-ink .dash-tab-btn,
.rail-nav.has-ink .dash-tab-btn:hover,
.rail-nav.has-ink .dash-tab-btn.active { background: none; box-shadow: none; }
.rail-nav.has-ink .dash-tab-btn:hover,
.rail-nav.has-ink .dash-tab-btn.active { color: rgba(250, 248, 243, .9); }
.rail-nav.has-ink .dash-tab-btn.is-lit,
.rail-nav.has-ink .dash-tab-btn.is-lit:hover { color: var(--navy); }
.rail-nav.has-ink .dash-tab-btn.is-lit .tab-count { color: var(--muted); }
/* the focus ring goes inside the pill, so it reads as part of the same shape */
.rail-nav.has-ink .dash-tab-btn:focus-visible {
  outline: 2px solid var(--cream); outline-offset: -3px; border-radius: 999px;
}
/* THE PILL DOES NOT SLIDE FOR SOMEONE WHO ASKED FOR NO MOTION. It still moves,
   because where it is IS the information; it simply arrives. */
@media (prefers-reduced-motion: reduce) { .rail-ink { transition: none; } }

/* ---- THE WAY OUT -------------------------------------------------------- */
.rail-sec { position: relative; z-index: 1; padding: 16px 0 0; }
.rail-more {
  display: inline-block; margin: 12px 0 0;
  font-family: var(--sans); font-size: 10px; font-weight: 600;
  letter-spacing: .12em; text-transform: uppercase;
  color: rgba(250, 248, 243, .72);
  box-shadow: inset 0 -1px 0 rgba(250, 248, 243, .35);
}
.rail-more:hover { color: var(--cream); box-shadow: inset 0 -1px 0 var(--cream); }

/* ══ THE WALL OPENS AND SHUTS ═════════════════════════════════════════════
   Everything below is scoped to `.has-drawer`, a class the script sets once it
   has the button, the scrim and the escape key wired together. Without the
   script the panel is where it has always been, in the flow at 258px, and
   there is no button that does nothing. Same rule as the pill, same reason. */
.rail-toggle, .rail-stub, .rail-scrim { display: none; }

/* THE MASTHEAD STAYS PINNED, AND ABOVE THE WALL.            ·  7 Sep 2026
   `hyyryn-account.css` gives it `z-index: 100` at (0,1,1) and the wall and its
   scrim sit at 120 and 119, both absolutely positioned inside a shell that
   scrolls under the bar. Without this the scrim paints OVER the masthead and
   dims the one thing that has to stay usable while the panel is open, which is
   exactly what happened on the second page to take this panel: the fix had
   been made in the first page's own sheet and did not travel.

   Named against the same ancestor and won on count, (0,1,2) against the shared
   file's (0,1,1). It only applies where this sheet is loaded, so no other
   masthead is touched. */
html header.topbar { z-index: 140; }

/* ---- THE PILASTER ------------------------------------------------------- */
.has-drawer .rail-stub {
  display: block; grid-column: 1; align-self: stretch;
  position: relative; z-index: 130; width: 38px;
}
.has-drawer .rail-toggle {
  position: sticky; top: calc(74px + clamp(14px, 1.6vw, 24px));
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; padding: 0;
  background: var(--cream); border: 1px solid var(--line); border-radius: 999px;
  color: var(--navy); cursor: pointer;
  /* The only pinned thing on the page, so it is a raised thing over whatever
     happens to be under it: a contact line and a near shadow, tinted with the
     site's dark, never black. */
  box-shadow: 0 1px 2px rgba(10, 22, 40, .14), 0 6px 14px -8px rgba(10, 22, 40, .34);
  transition: background 160ms ease, border-color 160ms ease,
              color 160ms ease, box-shadow 160ms ease;
}
.has-drawer .rail-toggle svg {
  width: 18px; height: 18px; fill: none; stroke: currentColor;
  stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round;
}
.has-drawer .rail-toggle:hover,
.has-drawer .rail-toggle:focus-visible { background: var(--cream-2); border-color: var(--line-2); }
/* OPEN IS IN THE GLYPH, NOT IN THE GROUND. Filling the ground went navy on
   navy while the wall was behind the button and near invisible on cream once
   the wall had scrolled away, because the wall leaves and the button does not.
   A cream disc reads on both, so the ground stays and the bay fills instead,
   which is what an open sidebar looks like everywhere. */
.has-drawer .rail-toggle .rt-bay { fill: none; stroke: none; transition: fill 160ms ease; }
.has-drawer .rail-toggle.is-open .rt-bay { fill: currentColor; }

/* ---- THE SHELL, WITH THE WALL OUT OF THE FLOW --------------------------- */
.has-drawer .dash-shell {
  position: relative;
  grid-template-columns: auto minmax(0, 1fr);
  margin-left: 0; gap: clamp(14px, 1.6vw, 24px);
}
.has-drawer .dash-body { grid-column: 2; }

.has-drawer .dash-rail {
  position: absolute; top: 0; bottom: 0; height: auto;
  /* Painted from page zero: exactly the box the wall occupied when it was in
     the flow, so opening it restores the left of the page to the pixel. */
  left: calc(-1 * var(--edge));
  width: min(258px, 86vw);
  z-index: 120; display: block;
  max-height: none; align-self: auto; margin: 0;
  background: none; overflow: visible; pointer-events: none;
  /* AND IT CASTS NOTHING. A shadow is right for a wall and wrong for a track:
     an invisible box the height of the page was throwing one down the whole
     left of it. The wall carries it, where there is something to be raised. */
  box-shadow: none;
  translate: -101% 0; visibility: hidden;
  transition: translate 340ms cubic-bezier(.22, .85, .3, 1),
              visibility 0s linear 340ms;
}
/* `visibility` rather than `display`, so the pill inside can still measure
   itself with `offsetLeft`, and so a closed wall is out of the tab order
   without anything having to manage `tabindex`. */
.has-drawer .dash-rail[data-open] {
  translate: 0 0; visibility: visible;
  transition: translate 340ms cubic-bezier(.22, .85, .3, 1);
}

/* THE WALL FILLS THE OPENING, MASTHEAD TO FOOTER. Sticky at an offset and only
   as tall as its contents leaves a slot at the head and another at the foot,
   and both show the scrimmed page sliding through, which is the one thing a
   pinned panel must not do. A wall does not float in an opening, it fills it:
   top at the masthead's underside, height the rest of the window, and the
   track's bottom stops it on the footer where navy meets navy. The offset that
   came off the sticky `top` goes onto the padding, so nothing inside moves. */
.has-drawer .rail-in {
  position: sticky; top: 74px;
  height: calc(100vh - 74px); max-height: calc(100vh - 74px);
  overflow-y: auto; overscroll-behavior: contain;
  background: var(--navy); pointer-events: auto;
  display: flex; flex-direction: column; gap: 20px;
  width: 100%; min-width: 0; max-width: none; box-sizing: border-box;
  padding: calc(26px + clamp(14px, 1.6vw, 24px)) var(--edge) 34px;
  box-shadow: none;
  transition: box-shadow 340ms ease;
}
/* NO SHADE ALONG THE FOOT. A dark hairline between a wall and the plinth it
   stands on is a wall that is not standing on it. Light on the top and left,
   shade on the right only, and the foot meets the plinth as a colour change. */
.has-drawer .dash-rail[data-open] .rail-in {
  box-shadow: inset 1px 1px 0 rgba(250, 248, 243, .14),
              inset -1px 0 0 rgba(0, 0, 0, .30),
              24px 0 60px -30px rgba(4, 9, 15, .78);
}

/* ---- THE SCRIM ---------------------------------------------------------- */
/* Bled one edge each side so it covers the page's full width, and nought top
   and bottom so it covers the shell's height and not one pixel more. The
   masthead and the footer are outside it and stay usable. */
.has-drawer .rail-scrim {
  display: block; position: absolute; top: 0; bottom: 0;
  left: calc(-1 * var(--edge)); right: calc(-1 * var(--edge));
  z-index: 119; background: rgba(4, 9, 15, .46);
  opacity: 0; pointer-events: none;
  transition: opacity 340ms ease;
}
.has-drawer .rail-scrim[data-open] { opacity: 1; pointer-events: auto; }

/* ---- LYING DOWN --------------------------------------------------------- */
/* A picture stretched to fill a row is a picture stretched, so the ground goes
   and the stack stops being a stack. */
@media (max-width: 980px) {
  .dash-shell { margin-left: 0; gap: 24px; grid-template-columns: minmax(0, 1fr); }
  .dash-rail { display: flex; }
  .rail-in {
    position: static; max-height: none; overflow: visible; height: auto;
    flex-direction: row; flex-wrap: wrap; align-items: center; padding: 20px;
  }
  .rail-night { display: none; }
  .rail-stack { display: contents; }
  .rail-nav { max-width: 100%; min-width: 0; flex-direction: row; width: 100%; overflow-x: auto; gap: 4px; }

  /* A 38px column beside the content would cost 54 of a 343px phone, so the
     pilaster becomes the first ROW, still sticky and still on the left.
     AND IT STRETCHES: sticky travels inside its containing block, so a stub
     38px tall cannot travel at all and the button would scroll off the top of
     a phone with the only way back into the panel gone. */
  .has-drawer .dash-shell { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .has-drawer .rail-stub {
    grid-column: 1; grid-row: 1; align-self: stretch; height: auto;
    pointer-events: none;
  }
  .has-drawer .dash-body { grid-column: 1; grid-row: 1; padding-top: 52px; }
  .has-drawer .rail-toggle { top: calc(64px + 12px); pointer-events: auto; }
  .has-drawer .dash-rail { width: min(288px, 86vw); }
  .has-drawer .rail-in {
    top: 64px; height: calc(100vh - 64px); max-height: calc(100vh - 64px);
    flex-direction: column; flex-wrap: nowrap; align-items: stretch;
    padding: 36px 20px 30px;
  }
  .has-drawer .rail-nav { flex-direction: column; overflow: visible; width: 100%; gap: 2px; }
  .has-drawer .dash-body { padding-bottom: clamp(40px, 5vw, 64px); }
}
@media (prefers-reduced-transparency: reduce) { .rail-night { opacity: 1; } }
