/* =============================================================================
   Gilead Press, layout

   Containers, grids, the masthead, the mobile sheet, the closing band, and the
   page shells. Anything that positions a region rather than styling a thing.
   ========================================================================== */

/* -----------------------------------------------------------------------------
   Containers and bands
   -------------------------------------------------------------------------- */

.container {
  width: 100%;
  max-width: var(--gp-page-max);
  margin-inline: auto;
  padding-inline: var(--gp-gutter);
}

.container--narrow {
  max-width: var(--gp-content-max);
}

.container--prose {
  max-width: var(--gp-measure-prose);
}

/* A band is a full-width horizontal region. Its ground is paper unless it is
   .band, which is the single Deep Forest closing band. */
.section {
  padding-block: var(--gp-band-pad);
}

.section--tight  { padding-block: var(--gp-space-40); }
.section--tight .section__head { margin-bottom: var(--gp-space-16); }
.section--sunken { background: var(--gp-surface-sunken); }

/* The rule between two paper sections, so they read as separate without a
   second background colour doing the work. */
.section--ruled {
  border-top: 1px solid var(--gp-rule);
}

.section__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--gp-space-16);
  margin-bottom: var(--gp-space-32);
}

.section__head p {
  color: var(--gp-ink-muted);
  margin-top: var(--gp-space-8);
  max-width: var(--gp-measure-prose);
}

/* -----------------------------------------------------------------------------
   The one Deep Forest band. Used by the footer, and by at most one closing
   region per page. Green coverage stays under roughly ten percent of a screen.
   -------------------------------------------------------------------------- */

.band {
  background: var(--gp-band);
  color: var(--gp-on-band);
}

.band h1,
.band h2,
.band h3,
.band h4 {
  color: var(--gp-on-band);
}

/* Sage Gray is 2.37:1 on Deep Forest. Muted text on the band is Pale Sage. */
.band .t-meta,
.band .t-muted {
  color: var(--gp-on-band-muted);
}

.band a {
  color: var(--gp-on-band);
}

.band a:hover {
  color: var(--gp-on-band-accent);
}

/* -----------------------------------------------------------------------------
   Grids
   -------------------------------------------------------------------------- */

.grid {
  display: grid;
  gap: var(--gp-space-24);
}

.grid--2 { grid-template-columns: 1fr; }
.grid--3 { grid-template-columns: 1fr; }
.grid--4 { grid-template-columns: 1fr; }

@media (min-width: 480px) {
  .grid--2,
  .grid--4 { grid-template-columns: repeat(2, 1fr); }
}

/* =============================================================================
   The subject grid: three across, then two across, each row full width.

   WHY SIX COLUMNS. Three items and two items have to divide the same width
   evenly, and six is the smallest number both go into. The top row takes two
   columns per card, the bottom row takes three. No percentages, no negative
   margins, no fractional rounding to argue with.

   WHY A QUANTITY QUERY. The 3 + 2 shape is only correct when there are
   exactly five subjects. Rather than bake that into a class name somebody has
   to remember to change, the rule asks the DOM how many children there are:
   `:first-child:nth-last-child(5)` matches only when the first child is also
   the fifth from the end. Add a sixth subject and every rule below stops
   matching, and the plain even grid underneath takes over on its own. That
   is the difference between a layout that adapts and a layout that has to be
   maintained.

   CROSS-BROWSER. Grid, `gap` on grid, `:nth-last-child`, `:nth-child(n + 4)`
   and the general sibling combinator are all CSS Selectors Level 3 or CSS
   Grid Level 1, supported in every browser this shop ships to, Safari on iOS
   included. Nothing here uses `:has()`, `subgrid` or container queries: those
   are the three that would genuinely have narrowed support, and the first
   draft of this rule reached for `:has()` before it was rewritten out.
   
   A browser that somehow applied the columns but not the spans gets a plain
   six-column grid: a worse layout, not a broken one.
   ========================================================================== */

/* One column on a phone. A subject card at a third of 360px is a word. */
.grid--subjects { grid-template-columns: 1fr; }

@media (min-width: 480px) {
  .grid--subjects { grid-template-columns: repeat(2, 1fr); }
}

@media (min-width: 768px) {
  /* Six columns ALWAYS at this width, never conditionally.
     
     The first draft of this rule switched the column count with :has(), and
     then carried a comment claiming it used no :has() at all. Beyond being
     untrue, :has() is the one selector here that would genuinely have narrowed
     support, which is the opposite of what was asked for. It is not needed:
     six columns with a default span of two IS three per row, so the container
     never has to know how many children it holds. Only the exception does. */
  .grid--subjects { grid-template-columns: repeat(6, 1fr); }

  /* Default: two columns each, which is three across. Every count that is not
     five lands here and stays a legible three-per-row grid. */
  .grid--subjects > * { grid-column: span 2; }

  /* THE EXCEPTION, and the whole point of the section.
     
     `:first-child:nth-last-child(5)` matches only when the first child is also
     the fifth from the end, which is a way of asking "are there exactly five
     of you" in plain CSS. Combined with `~ :nth-child(n + 4)` it selects the
     fourth and fifth cards and gives them half the row each.
     
     Add a sixth subject and this stops matching entirely, on its own, and the
     default above takes over. Nobody has to remember to change a class. */
  .grid--subjects > :first-child:nth-last-child(5) ~ :nth-child(n + 4) {
    grid-column: span 3;
  }
}

/* The feature grid, for the two horizontal cards below the catalogue row.

   It is NOT .grid--2, which goes two-up at 480px. A feature card is
   horizontal: it spends 168px of its width on the cover before any text
   starts, so at 480px in two columns it has about 70px left for a title and a
   sentence, which is a card that has been folded into a column of single
   words. It stays one-up until there is genuinely room for two, which is
   1024px, where each card gets roughly 570px. */
.grid--feature {
  grid-template-columns: 1fr;
  gap: var(--gp-space-24);
}

@media (min-width: 1024px) {
  .grid--feature {
    grid-template-columns: repeat(2, 1fr);
    gap: var(--gp-space-32);
  }
}

@media (min-width: 768px) {
  .grid--3 { grid-template-columns: repeat(3, 1fr); }
}

@media (min-width: 1024px) {
  .grid--4 { grid-template-columns: repeat(4, 1fr); }
}

/* The catalogue grid: ONE on a phone, TWO on a tablet, THREE on a desktop.

   It was two-up on the phone, on the reasoning that a single column of covers
   is a long page for little information. That was the right trade when the
   cover was a small thumbnail; it is the wrong one now the cover band is a
   fixed height carrying a title that has to be legible. Two 170px covers side
   by side on a 390px screen put the title back to unreadable, which is the
   whole problem the fixed band was introduced to solve. */
.grid--catalogue {
  grid-template-columns: 1fr;
  gap: var(--gp-space-24);
}

@media (min-width: 640px) {
  .grid--catalogue {
    grid-template-columns: repeat(2, 1fr);
    gap: var(--gp-space-24);
  }
}

@media (min-width: 1024px) {
  .grid--catalogue {
    grid-template-columns: repeat(3, 1fr);
    gap: var(--gp-space-32);
  }
}

/* THREE ACROSS, and no more.

   It went to four at 1024px when the filters lived in a left rail and the grid
   had to earn back the width. The filters are a toolbar across the top now, so
   the grid has the whole container and can afford to let each cover breathe.
   Three matches the home page's featured row, so a visitor moving from one to
   the other sees the same shelf. */

/* A rail: horizontal snap-scroll under 640px, a grid above it. Used by the
   home page's featured block. The card width is 72% of the viewport so the
   next card is visibly cut off and the row reads as scrollable. A grid of four
   covers on a 360px screen makes each cover 160px wide and unreadable. */
.rail {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 72%;
  gap: var(--gp-space-16);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: thin;

  /* The rail breaks out of the container's gutter and re-applies it as its own
     padding, so the row can scroll edge to edge while the first and last cards
     still line up with the heading above them.

     scroll-padding-inline is the half that gets forgotten: without it the
     snap points sit at the scroll container's edge, so every card after the
     first snaps flush against the side of the screen with no gutter at all.
     padding-inline positions the cards at rest; scroll-padding-inline
     positions them once you start swiping. Both are needed. */
  margin-inline: calc(var(--gp-gutter) * -1);
  padding-inline: var(--gp-gutter);
  scroll-padding-inline: var(--gp-gutter);
  padding-bottom: var(--gp-space-8);
}

.rail > * {
  scroll-snap-align: start;
}

@media (min-width: 640px) {
  .rail {
    grid-auto-flow: row;
    grid-template-columns: repeat(2, 1fr);
    grid-auto-columns: auto;
    overflow: visible;
    margin-inline: 0;
    padding-inline: 0;
    gap: var(--gp-space-24);
  }
}

/* THREE across, not four.

   Four covers across a 1200px container gives each card roughly 270px, and at
   that width the cover band has to carry a title that was set for a full page.
   Three gives each card roughly 370px, which is where these covers become
   legible and where the card stops looking like a thumbnail. The featured
   block is owner-curated and takes a row, so a row is three. */
@media (min-width: 1024px) {
  .rail {
    grid-template-columns: repeat(3, 1fr);
    gap: var(--gp-space-32);
  }
}

/* A two-column split: content and a sidebar that becomes a sticky rail on
   desktop. The selling page and the checkout both use it. */
.split {
  display: grid;
  gap: var(--gp-space-32);
}

@media (min-width: 1024px) {
  .split {
    grid-template-columns: minmax(0, 1fr) 360px;
    gap: var(--gp-space-64);
    align-items: start;
  }

  .split__aside {
    position: sticky;
    top: calc(var(--gp-header-h) + var(--gp-space-24));
  }
}

.split--reverse .split__aside { order: -1; }

/* Checkout: summary first on mobile, then a wider RIGHT column on desktop.

   `.split` puts the aside second on mobile, which is wrong here: buyers check
   what they are paying for before they think about how. `.split--reverse`
   fixes the mobile order but then drops the aside into a 300px LEFT rail.
   This is the combination the checkout actually needs, and it is a modifier
   rather than a one-off because the receipt page wants the same shape. */
.split--summary-first .split__aside { order: -1; }

@media (min-width: 1024px) {
  .split--summary-first {
    grid-template-columns: minmax(0, 1fr) 380px;
  }
  .split--summary-first .split__aside { order: 0; }
}

@media (min-width: 1024px) {
  .split--reverse {
    grid-template-columns: 300px minmax(0, 1fr);
  }
  .split--reverse .split__aside { order: 0; }
}

/* -----------------------------------------------------------------------------
   The masthead

   Sticky, on paper, with a hairline that only appears once the page has
   scrolled. It does not block on the auth request: it renders the signed-out
   shape and swaps when the session resolves. There is no skeleton in the
   header, because a grey pill where the sign-in link goes is more alarming
   than the link appearing 200ms late.
   -------------------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: var(--gp-z-header);
  background: var(--gp-ground);
  border-bottom: 1px solid transparent;
  transition: border-color var(--gp-dur-micro) var(--gp-ease-out),
              box-shadow var(--gp-dur-micro) var(--gp-ease-out);
}

.site-header.is-scrolled {
  border-bottom-color: var(--gp-rule);
  box-shadow: var(--gp-elevation-1);
}

.site-header__inner {
  display: flex;
  align-items: center;
  gap: var(--gp-space-16);
  min-height: var(--gp-header-h);
}

.site-header__logo {
  display: flex;
  align-items: center;
  margin-right: auto;
  text-decoration: none;
}

.site-header__logo img {
  height: 32px;
  width: auto;
}

@media (min-width: 1024px) {
  .site-header__logo img { height: 38px; }
}

/* The desktop nav AND the header actions are hidden under 768px, where the
   sheet takes over. Both, not just the nav: My Library and Sign in already
   live inside the sheet, and leaving them in the bar as well put three
   competing controls next to a Menu button on a 390px screen. */
.nav,
.site-header__actions {
  display: none;
}

/* The group is a row, not a block.
   
   It had no rule at all, and got away with it for as long as it only ever
   held inline <a> elements, which flow side by side on their own. The moment
   the account menu arrived as a <div>, it dropped onto its own line and left
   My Library stacked above the avatar.
   
   Declared outside the desktop media query on purpose: the parent
   .site-header__actions is display:none below that breakpoint, so the group
   is never laid out there anyway, and one rule is easier to reason about
   than a rule that only exists at one width. */
.site-header__actions-group {
  display: flex;
  align-items: center;
  gap: var(--gp-space-16);
}

/* The list is a semantic wrapper only: the flex row is .nav itself, so the ul
   dissolves out of the layout. This is a rule rather than an inline style
   because it is chrome, and chrome is copied into 30 templates. */
.nav__list {
  display: contents;
  list-style: none;
  margin: 0;
  padding: 0;
}

@media (min-width: 768px) {
  .nav {
    display: flex;
    align-items: center;
    gap: var(--gp-space-4);
  }

  .site-header__actions {
    display: flex;
    align-items: center;
    gap: var(--gp-space-16);
  }
}

.nav__link {
  display: inline-flex;
  align-items: center;
  gap: var(--gp-space-4);
  padding: var(--gp-space-8) var(--gp-space-12);
  border-radius: var(--gp-radius);
  font-size: var(--gp-fs-small);
  font-weight: var(--gp-fw-medium);
  color: var(--gp-ink);
  text-decoration: none;
  white-space: nowrap;
}

.nav__link:hover {
  color: var(--gp-accent-face);
  background: var(--gp-surface);
}

/* The current page is marked with ONE UNDERLINE and nothing else.

   It was an inset box-shadow across the full padded width of the link, which
   read as a thick olive bar floating under a pill rather than as an underline
   on a word. The rule now sits inside the link's padding so it underlines the
   TEXT, which is what an underline is. */
.nav__link[aria-current='page'] {
  color: var(--gp-ink);
  font-weight: var(--gp-fw-semi);
  position: relative;
}

.nav__link[aria-current='page']:after {
  content: '';
  position: absolute;
  left: var(--gp-space-12);
  right: var(--gp-space-12);
  bottom: 2px;
  height: 2px;
  border-radius: 1px;
  background: var(--gp-accent-face);
}

.nav__link[aria-current='page']:hover { background: transparent; }

/* A nav item with a subject menu under it. */
.nav__item {
  position: relative;
}

.nav__menu {
  position: absolute;
  top: calc(100% + var(--gp-space-8));
  left: 0;
  min-width: 240px;
  padding: var(--gp-space-8);
  background: var(--gp-surface);
  border: 1px solid var(--gp-rule);
  border-radius: var(--gp-radius);
  box-shadow: var(--gp-elevation-3);
  list-style: none;
  margin: 0;
}

.nav__menu[hidden] { display: none; }

/* Same box for the empty rows, which are spans rather than anchors. See the
   note on .sheet__sub: a rule written only for `a` drops them to inline. */
.nav__menu a,
.nav__menu .is-empty {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--gp-space-16);
  padding: var(--gp-space-8) var(--gp-space-12);
  border-radius: var(--gp-radius-sm);
  font-size: var(--gp-fs-small);
  color: var(--gp-ink);
  text-decoration: none;
}

.nav__menu a:hover {
  background: var(--gp-surface-sunken);
  color: var(--gp-accent-face);
}

.nav__menu-count {
  font-size: var(--gp-fs-meta);
  color: var(--gp-ink-muted);
}

.nav__menu-rule {
  height: 1px;
  background: var(--gp-rule);
  margin: var(--gp-space-8) var(--gp-space-12);
}

/* The menu button. Visible under 768px only. */
.nav__toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--gp-space-8);
  padding: var(--gp-space-8) var(--gp-space-12);
  border: 1px solid var(--gp-rule-strong);
  border-radius: var(--gp-radius);
  font-size: var(--gp-fs-small);
  font-weight: var(--gp-fw-medium);
  color: var(--gp-ink);
}

@media (min-width: 768px) {
  .nav__toggle { display: none; }
}

/* -----------------------------------------------------------------------------
   The mobile sheet

   Full height from the right. Traps focus, closes on Escape, returns focus to
   the menu button, and applies inert to the page behind it.
   -------------------------------------------------------------------------- */

.scrim {
  position: fixed;
  inset: 0;
  z-index: var(--gp-z-scrim);
  background: var(--gp-scrim);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--gp-dur-sheet) var(--gp-ease),
              visibility var(--gp-dur-sheet);
}

.scrim.is-visible {
  opacity: 1;
  visibility: visible;
}

.sheet {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: var(--gp-z-sheet);
  width: min(92vw, 380px);
  display: flex;
  flex-direction: column;
  background: var(--gp-surface);
  transform: translateX(100%);
  transition: transform var(--gp-dur-sheet) var(--gp-ease);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.sheet[data-open='true'] {
  transform: none;
}

.sheet__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gp-space-16);
  padding: var(--gp-space-16) var(--gp-space-24);
  border-bottom: 1px solid var(--gp-rule);
}

.sheet__head img { height: 30px; width: auto; }

.sheet__body {
  padding: var(--gp-space-16) var(--gp-space-24) var(--gp-space-32);
}

.sheet__list {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Primary and secondary are typographically distinct, because blurring the two
   is a cognitive competition the reader has to resolve for no reason. */
.sheet__link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gp-space-12);
  width: 100%;
  padding: var(--gp-space-12) 0;
  font-size: 18px;
  font-weight: var(--gp-fw-semi);
  color: var(--gp-ink);
  text-decoration: none;
}

.sheet__link--secondary {
  font-size: 15px;
  font-weight: var(--gp-fw-regular);
  color: var(--gp-ink-muted);
}

/* The signed-in group's heading: the buyer's own name, filled in by nav.js.
   It used to be a <span> wearing .sheet__link, which made it look like the
   links either side of it while being neither clickable nor labelled as
   anything. A screen reader read it as a stray line of text between two
   links. It is a heading for the list beneath it, so it is styled as one. */
.sheet__label {
  margin: var(--gp-space-16) 0 var(--gp-space-4);
  font-size: 13px;
  font-weight: var(--gp-fw-semi);
  color: var(--gp-ink-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  /* A long display name wraps rather than widening the sheet. */
  overflow-wrap: anywhere;
}

/* The sheet carries the same mark as the bar, for the same reason: a reader
   who opens the menu should be able to see where they already are. Same
   underline, sized to the sheet's larger type. */
.sheet__link[aria-current='page'] {
  position: relative;
  color: var(--gp-ink);
}

.sheet__link[aria-current='page']:after {
  content: '';
  position: absolute;
  left: 0;
  bottom: var(--gp-space-8);
  width: 2ch;
  height: 2px;
  border-radius: 1px;
  background: var(--gp-accent-face);
}

.sheet__rule {
  height: 1px;
  background: var(--gp-rule);
  margin: var(--gp-space-16) 0;
}

/* Subjects sit inside Books and Courses as a disclosure rather than as a flat
   list, because six to ten flat subject links in a sheet buries the two items
   that actually carry traffic. */
/* ---------- THE SUBJECT SUBMENU IN THE MOBILE SHEET ----------

   WHAT WAS WRONG WITH THE LEFT RULE. It was a 2px Pale Sage line down the left
   of the list, and it failed at both jobs a line like that can have. It did not
   ATTACH the list to the trigger above it: it started at the first item and
   ended at the last, touching neither, so it read as a stranded mark rather
   than as a bracket. And it did not SEPARATE the list from the sheet: Pale
   Sage on white is 1.27, so on a phone in daylight it is nearly gone, leaving
   an indent with a smudge beside it.

   A rule can indicate nesting or it can indicate grouping. This one was asked
   to do both and did neither, which is why it looked like a leftover.

   WHAT REPLACES IT. The list becomes a surface. A sunken panel inset from the
   sheet's own padding says "these belong to the item above" the way an indent
   plus a hairline was trying to and failing, and it says it at a glance rather
   than at a squint. Nesting is then carried by the inset and the fill, not by
   a line that has to be seen to work.

   AND THE ROWS BECOME TARGETS. They were 15px muted text on 16px of leading:
   about 32px tall, under the 44px minimum this codebase holds everywhere else,
   and set in the same muted ink as help text, so a list of four places you can
   go looked like a paragraph. They are now full-width rows at 44px, in body
   ink, that highlight under a thumb. */

.sheet__sub {
  list-style: none;
  margin: var(--gp-space-4) 0 var(--gp-space-12);
  padding: var(--gp-space-4);
  border-radius: var(--gp-radius);
  background: var(--gp-surface-sunken);
}

/* THE EMPTY ROWS TAKE THE SAME BOX AS THE LINKS. They are spans, not anchors,
   because an empty subject is not clickable, and a rule written only for `a`
   drops them back to inline: no row, no min-height, the count crammed against
   the name. They are the same row, they simply do not navigate. */
.sheet__sub a,
.sheet__sub .is-empty {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gp-space-12);
  min-height: 44px;
  padding: var(--gp-space-8) var(--gp-space-12);
  border-radius: var(--gp-radius-sm);
  font-size: var(--gp-fs-small);
  font-weight: var(--gp-fw-medium);
  color: var(--gp-ink);
  text-decoration: none;
}

/* The hovered row lifts to the sheet's own surface rather than darkening. On a
   sunken panel that is the direction that reads as "this one", and it needs no
   new colour to do it. */
.sheet__sub a:hover {
  background: var(--gp-surface);
  color: var(--gp-accent-face);
}

/* THE COUNT IS THERE TO PREVENT A WASTED TAP. Three of the four subjects have
   no titles in them yet, and a reader who taps Faith on a phone, waits for a
   page and finds an empty shelf has been sent somewhere for nothing. The
   number is the same fact the homepage's subject cards already state, so the
   two cannot disagree. */
.sheet__sub-count {
  flex: none;
  font-size: var(--gp-fs-meta);
  font-weight: var(--gp-fw-regular);
  color: var(--gp-ink-muted);
  font-variant-numeric: tabular-nums;
}

/* An empty subject is still listed, because the catalogue is built to take
   more and hiding it would make the shop look smaller than it is. It is
   listed HONESTLY: the row is quieter and says so in words rather than
   printing a zero, which reads as a bug more often than as a count. */
.sheet__sub a:has(.sheet__sub-count--empty) { color: var(--gp-ink-muted); }

/* The trigger owns the list under it, so the chevron turns with it. Every
   other disclosure in this build does this; the sheet was the one that did
   not, which left the control looking inert at the moment it did the most. */
.sheet__link[aria-expanded] .icon {
  transition: transform var(--gp-dur-accordion) var(--gp-ease-out);
}

.sheet__link[aria-expanded='true'] .icon { transform: rotate(180deg); }

/* -----------------------------------------------------------------------------
   Breadcrumbs

   On mobile the trail scrolls horizontally rather than truncating with an
   ellipsis: a truncated breadcrumb that cannot be scrolled has thrown away the
   wayfinding it existed to provide.
   -------------------------------------------------------------------------- */

.breadcrumb {
  padding-top: var(--gp-space-24);
}

.breadcrumb ol {
  display: flex;
  align-items: center;
  gap: var(--gp-space-8);
  list-style: none;
  margin: 0;
  padding: 0;
  overflow-x: auto;
  scrollbar-width: none;
  white-space: nowrap;
  font-size: var(--gp-fs-meta);
  color: var(--gp-ink-muted);
}

.breadcrumb ol:-webkit-scrollbar { display: none; }

.breadcrumb li {
  display: flex;
  align-items: center;
  gap: var(--gp-space-8);
}

.breadcrumb li + li:before {
  content: '/';
  color: var(--gp-rule-strong);
}

.breadcrumb a {
  color: var(--gp-ink-muted);
  text-decoration: none;
}

.breadcrumb a:hover {
  color: var(--gp-accent);
  text-decoration: underline;
}

.breadcrumb [aria-current='page'] {
  color: var(--gp-ink);
}

/* -----------------------------------------------------------------------------
   The page head: breadcrumb, h1, standfirst. Used by every interior page.
   -------------------------------------------------------------------------- */

.page-head {
  padding-block: var(--gp-space-32) var(--gp-space-40);
}

/* A section that follows the page head does not re-pay for the space the head
   has already left. The two were stacking to roughly 120px of empty page
   between the standfirst and the first line of content. */
.page-head + .section {
  padding-top: 0;
}

.page-head h1 {
  margin-top: var(--gp-space-16);
}

.page-head__lead {
  margin-top: var(--gp-space-16);
  max-width: var(--gp-measure-prose);
  font-size: var(--gp-fs-lead);
  line-height: var(--gp-lh-lead);
  color: var(--gp-ink-muted);
}

/* -----------------------------------------------------------------------------
   The closing footer band
   -------------------------------------------------------------------------- */

/* The gap above the closing band exists for pages whose last block is not a
   padded section. A page that DOES end in a section already carries that
   section's bottom padding, and adding the margin on top of it opened roughly
   160px of dead ground between the last content and the band. */
.site-footer {
  margin-top: var(--gp-space-64);
}

:where(.section, .section--tight) + .site-footer,
main:has(> .section:last-child) + .site-footer {
  margin-top: 0;
}

.site-footer__lead {
  font-family: var(--gp-font-display);
  font-size: var(--gp-fs-h3);
  line-height: var(--gp-lh-h3);
  max-width: 22ch;
  padding-bottom: var(--gp-space-32);
  border-bottom: 1px solid var(--gp-rule-on-band);
  margin-bottom: var(--gp-space-32);
}

@media (min-width: 768px) {
  .site-footer__lead { max-width: 34ch; }
}

/* The footer grid is the brand column PLUS the four link groups.

   At 1024px the brand column is wider than a link column and comes first, so
   the imprint identifies itself before it lists its pages. Below that the
   brand column spans the full width and the link groups sit under it as
   accordions, which is why it is a `2fr` rather than a fifth equal column. */
.site-footer__grid {
  display: grid;
  gap: 0;
}

@media (min-width: 640px) {
  .site-footer__grid {
    grid-template-columns: repeat(2, 1fr);
    gap: var(--gp-space-32);
  }

  .site-footer__brand { grid-column: 1 / -1; }
}

@media (min-width: 1024px) {
  .site-footer__grid {
    grid-template-columns: 1.6fr repeat(4, 1fr);
    gap: var(--gp-space-40);
  }

  .site-footer__brand { grid-column: auto; }
}

/* ---------- The brand column ---------- */

.site-footer__brand {
  padding-bottom: var(--gp-space-32);
}

@media (min-width: 1024px) {
  .site-footer__brand { padding-bottom: 0; }
}

.site-footer__mark img {
  height: 52px;
  width: auto;
}

@media (min-width: 1024px) {
  .site-footer__mark img { height: 60px; }
}

.site-footer__about {
  margin-top: var(--gp-space-16);
  max-width: 40ch;
  font-size: var(--gp-fs-small);
  line-height: var(--gp-lh-small);
  /* Pale Sage, not Sage Gray. Sage Gray is 2.14:1 on Deep Forest and is a
     light-surface ink only. */
  color: var(--gp-on-band-muted);
}

/* ---------- Social ----------

   A 44px target, a hairline ring rather than a filled disc, and the imprint's
   own ivory on hover. Each link carries a visually hidden name: an icon alone
   has no accessible name, and "link" is what a screen reader would otherwise
   announce four times. */

.social {
  display: flex;
  gap: var(--gp-space-8);
  list-style: none;
  margin: var(--gp-space-24) 0 0;
  padding: 0;
}

.social a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--gp-rule-on-band);
  border-radius: 50%;
  color: var(--gp-on-band-muted);
  transition: background-color var(--gp-dur-micro) var(--gp-ease-out),
              color var(--gp-dur-micro) var(--gp-ease-out),
              border-color var(--gp-dur-micro) var(--gp-ease-out);
}

.social a:hover {
  background: var(--gp-on-band);
  border-color: var(--gp-on-band);
  color: var(--gp-accent-face);
}

.social .icon { width: 20px; height: 20px; }

/* Under 640px each group is a disclosure. Above it, the button becomes a plain
   heading and the list is always open. */
.footer-group {
  border-bottom: 1px solid var(--gp-rule-on-band);
}

/* THE HEADING BELONGS TO THE LIST UNDER IT, AND THE SPACING HAS TO SAY SO.

   The old rhythm was: rule, 16px, HEADING, 16px, items 8px apart, 16px, rule.
   Every gap the same size. A heading floating equidistant between the boundary
   above it and the list below it belongs to neither, and the divider then
   reads as an underline for the items above rather than as a separator
   between two groups. That is the discrepancy: not one wrong number, but four
   identical ones where the design needed them to differ.

   It is now: rule, 24px, HEADING, 12px, items, 24px, rule. The heading sits
   twice as close to its own list as to the rule above it, which is the whole
   of the fix and the only thing proximity has to do here. */
.footer-group__toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: var(--gp-space-24) 0 var(--gp-space-12);
  font-family: var(--gp-font-body);
  font-size: var(--gp-fs-small);
  font-weight: var(--gp-fw-semi);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--gp-on-band);
  text-align: left;
}

.footer-group__toggle .icon {
  transition: transform var(--gp-dur-accordion) var(--gp-ease-out);
}

.footer-group__toggle[aria-expanded='true'] .icon {
  transform: rotate(180deg);
}

.footer-group__list {
  list-style: none;
  margin: 0;
  padding: 0 0 var(--gp-space-24);
}

/* THE ROWS CARRY THEIR OWN SPACE, rather than being 15px text pushed apart by
   an 8px margin. That gave rows about 23px tall in a footer where a thumb is
   the only input device, and this codebase holds a 44px minimum everywhere
   else. The padding is on the link, so the target is the padded box and not
   just the glyphs. */
.footer-group__list li + li { margin-top: 0; }

.footer-group__list a,
.footer-group__list .is-empty {
  display: flex;
  align-items: center;
  min-height: 44px;
  padding: var(--gp-space-4) 0;
  font-size: var(--gp-fs-small);
  color: var(--gp-on-band-muted);
  text-decoration: none;
}

.footer-group__list a:hover {
  color: var(--gp-on-band);
  text-decoration: underline;
}

@media (min-width: 640px) {
  .footer-group { border-bottom: 0; }

  .footer-group__toggle {
    pointer-events: none;
    padding-top: 0;
  }

  /* No rule below a column on desktop, so the 24px that separated one group
     from the next has nothing left to separate. The rows shrink back to
     reading size too: 44px targets are a phone requirement, and four columns
     of 44px rows on a desktop footer is a lot of empty band. */
  .footer-group__list { padding-bottom: 0; }

  .footer-group__list a,
  .footer-group__list .is-empty {
    min-height: 0;
    padding: var(--gp-space-4) 0;
  }

  .footer-group__toggle .icon { display: none; }

  /* The disclosure is a mobile affordance only, so the panel is always shown
     above the breakpoint even when the button says it is collapsed.

     content-visibility is not optional here. disclosure.js upgrades a closed
     panel to hidden="until-found" so find-in-page can match inside it, and the
     UA stylesheet implements that with `content-visibility: hidden` rather
     than `display: none`. Overriding display alone therefore produced a panel
     that was display:block and 0px tall, which is how the whole footer shipped
     empty on desktop the first time this was built. */
  .footer-group__list[hidden] {
    display: block !important;
    content-visibility: visible !important;
  }
}

.site-footer__bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--gp-space-24);
  padding-top: var(--gp-space-32);
  margin-top: var(--gp-space-32);
  border-top: 1px solid var(--gp-rule-on-band);
  font-size: var(--gp-fs-meta);
  color: var(--gp-on-band-muted);
}

/* -----------------------------------------------------------------------------
   The bare shells

   Checkout, the selling page at /l/:slug, and the five auth screens carry no
   header and no footer, so nothing on them invites an exit. They still need a
   mark and a way back, which is all the bare header is.
   -------------------------------------------------------------------------- */

.bare-header {
  padding-block: var(--gp-space-24);
  border-bottom: 1px solid var(--gp-rule);
}

.bare-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gp-space-16);
}

.bare-header img { height: 32px; width: auto; }

/* The right-hand end of the bare shell: who is buying, then the way back.
   
   A row rather than a block, because .site-header__actions-group taught this
   codebase the same lesson a week earlier: a wrapper with no rule is a block,
   and the moment a second element joins it, the two stack. */
.bare-header__end {
  display: flex;
  align-items: center;
  gap: var(--gp-space-16);
}

.bare-header__account {
  display: flex;
  align-items: center;
  gap: var(--gp-space-8);
  margin: 0;
  font-size: var(--gp-fs-meta);
  color: var(--gp-ink-muted);
}

/* The name wraps rather than pushing the back link off the row, and a long
   display name is truncated rather than allowed to dominate a checkout. */
.bare-header__account-name {
  max-inline-size: 22ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Below the point where both fit, the account line steps back rather than
   crowding the way out. The buyer can still see it on the checkout body. */
@media (max-width: 640px) {
  .bare-header__account { display: none; }
}

.bare-footer {
  padding-block: var(--gp-space-32);
  margin-top: var(--gp-space-64);
  border-top: 1px solid var(--gp-rule);
  font-size: var(--gp-fs-meta);
  color: var(--gp-ink-muted);
}

.bare-footer ul {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gp-space-16);
  list-style: none;
  margin: var(--gp-space-8) 0 0;
  padding: 0;
}

/* THE AUTH SHELL. No header, no footer, no navigation.

   Just the mark and one card, centred on the screen in both directions. An
   auth screen is a single task with a single control, and every other thing on
   it is something to tap instead of finishing.

   The CARD is centred, and so are the heading and the lead beneath it. The
   FIELDS are not: labels and inputs stay left-aligned, because centred form
   fields give the eye a new starting point on every row and are measurably
   slower to complete. Centring the container is not the same as centring the
   contents. */
.auth-shell {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: var(--gp-space-32) var(--gp-gutter);
  gap: var(--gp-space-32);
}

.auth-shell__logo img {
  height: 40px;
  width: auto;
}

.auth-card {
  width: 100%;
  max-width: 420px;
}

.auth-card h1 {
  font-size: var(--gp-fs-h2);
  line-height: var(--gp-lh-h2);
  text-align: center;
}

.auth-card__lead {
  margin-top: var(--gp-space-12);
  margin-bottom: var(--gp-space-32);
  text-align: center;
  font-size: var(--gp-fs-small);
  color: var(--gp-ink-muted);
}

/* A notice on the card sits apart from the form it is about. Every auth
   screen has one; without this the first field label touched its border. */
.auth-card .msg {
  margin-bottom: var(--gp-space-24);
}

/* "or" between the password form and the sign-in link button: a hairline
   either side of the word, so the two ways in read as alternatives. */
.auth-card__or {
  display: flex;
  align-items: center;
  gap: var(--gp-space-12);
  margin: var(--gp-space-24) 0 var(--gp-space-16);
  font-size: var(--gp-fs-meta);
  color: var(--gp-ink-muted);
}

.auth-card__or::before,
.auth-card__or::after {
  content: "";
  flex: 1;
  border-top: 1px solid var(--gp-rule);
}

/* The secondary doors under the form, and the legal line under the card. */
.auth-card__foot {
  margin-top: var(--gp-space-24);
  padding-top: var(--gp-space-24);
  border-top: 1px solid var(--gp-rule);
  text-align: center;
  font-size: var(--gp-fs-small);
}

.auth-shell__legal {
  text-align: center;
  font-size: var(--gp-fs-meta);
  color: var(--gp-ink-muted);
}

.auth-shell__legal a { color: var(--gp-ink-muted); }


/* =============================================================================
   THE DASHBOARD SHELL

   A fixed Deep Forest rail, a topbar, and a capped content column. Used by the
   seven customer account screens and nothing else: the class .gp-dashboard on
   the shell root is what switches the token layer on, so a public page cannot
   reach it.

   THREE THINGS THIS SHELL DOES THAT A STOREFRONT PAGE DOES NOT

   1. The rail is PERSISTENT at 1024px and above, and becomes the same sheet
      the storefront already uses below that. There is no second drawer
      implementation: nav.js already traps focus, closes on Escape and returns
      focus, and rebuilding that badly is how a dashboard becomes unusable by
      keyboard.
   2. The content column is CAPPED at 1120px, so a wider window grows the
      margins rather than the table. It is why this stays legible on a 27 inch
      monitor.
   3. A resting panel is FLAT, separated from the canvas by a hairline. Level 2
      elevation is for menus and popovers only. Reaching for a lifted card on a
      dense screen is how the screen turns into soup.
   ========================================================================== */

.dash {
  min-height: 100vh;
  background: var(--gp-dash-canvas);
}

@media (min-width: 1024px) {
  .dash {
    display: grid;
    grid-template-columns: var(--gp-dash-rail-width) minmax(0, 1fr);
    align-items: start;
  }
}

/* ---------- The rail ---------- */

.dash-rail {
  display: none;
  background: var(--gp-dash-rail);
  color: var(--gp-dash-rail-ink);
  /* Transparent in the light theme, where an 11.94 step already separates the
     rail from the page. In the dark the rail is 1.44 against the ground, which
     is not an edge, so the token becomes a real hairline there. */
  border-right: 1px solid var(--gp-dash-rail-edge);
}

@media (min-width: 1024px) {
  .dash-rail {
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 0;
    height: 100vh;
    overflow-y: auto;
  }
}

/* The mark at the top of the rail is a LINK HOME, not decoration. A customer
   inside their library still has a shop to go back to, and this is the way
   back. It is the reversed lockup because the rail is Deep Forest. */
.dash-rail__home {
  display: flex;
  align-items: center;
  gap: var(--gp-dash-space-3);
  padding: var(--gp-dash-space-5);
  min-height: var(--gp-dash-topbar-height);
  border-bottom: 1px solid var(--gp-rule-on-band);
  text-decoration: none;
}

.dash-rail__home img {
  height: 34px;
  width: auto;
}

.dash-rail__nav {
  flex: 1;
  padding: var(--gp-dash-space-5) var(--gp-dash-space-4);
}

.dash-rail__group + .dash-rail__group {
  margin-top: var(--gp-dash-space-6);
  padding-top: var(--gp-dash-space-5);
  border-top: 1px solid var(--gp-rule-on-band);
}

.dash-rail__label {
  padding: 0 var(--gp-dash-space-3) var(--gp-dash-space-3);
  font-size: var(--gp-dash-text-micro);
  letter-spacing: var(--gp-dash-tracking-micro);
  text-transform: uppercase;
  font-weight: var(--gp-fw-semi);
  color: var(--gp-dash-rail-ink-muted);
}

.dash-rail__list {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Space between items. A nav where the rows touch reads as one block of text
   rather than as a list of destinations, and the hover lift has no edge. */
.dash-rail__list li + li { margin-top: var(--gp-dash-space-2); }

.dash-rail__link {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--gp-dash-space-3);
  padding: var(--gp-dash-space-3);
  min-height: var(--gp-dash-control-height);
  border-radius: var(--gp-dash-radius-control);
  font-size: var(--gp-dash-text-body);
  color: var(--gp-dash-rail-ink-muted);
  text-decoration: none;
}

.dash-rail__link .icon { flex: none; }

.dash-rail__link:hover {
  background: var(--gp-dash-rail-lift);
  color: var(--gp-dash-rail-ink);
}

/* THE CURRENT ITEM. The lift is a surface and the marker is Soft Leaf, 4.09 on
   that lift, over the 3.0 that a non-text indicator needs. It marks WHERE YOU
   ARE, which is location and not state, so this is not green signalling
   status, and it is never the only signal: the item also carries
   aria-current. Green never signals state anywhere in this system. */
.dash-rail__link[aria-current='page'] {
  background: var(--gp-dash-rail-lift);
  color: var(--gp-dash-rail-ink);
  font-weight: var(--gp-fw-semi);
}

.dash-rail__link[aria-current='page']::before {
  content: '';
  position: absolute;
  left: calc(var(--gp-dash-space-3) * -1);
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 22px;
  border-radius: 0 2px 2px 0;
  background: var(--gp-dash-rail-marker);
}

.dash-rail__count {
  margin-left: auto;
  font-size: var(--gp-dash-text-meta);
  font-variant-numeric: tabular-nums;
  color: var(--gp-dash-rail-ink-muted);
}

.dash-rail__foot {
  padding: var(--gp-dash-space-4);
  border-top: 1px solid var(--gp-rule-on-band);
}

/* ---------- The topbar ---------- */

.dash-top {
  position: sticky;
  top: 0;
  z-index: var(--gp-z-header);
  display: flex;
  align-items: center;
  gap: var(--gp-dash-space-4);
  min-height: var(--gp-dash-topbar-height);
  padding: var(--gp-dash-space-4) var(--gp-gutter);
  background: var(--gp-dash-canvas);
  border-bottom: 1px solid var(--gp-dash-hairline);
}

@media (min-width: 1024px) {
  .dash-top { padding-inline: var(--gp-dash-page-gutter); }
}

/* Below 1024px the rail is gone, so the topbar carries the mark and the menu
   button that opens the same sheet the storefront uses. */
/* MOBILE HEADER ORDER: mark, then the icon controls, then the menu button.

   The mark comes first because it is the thing that says where you are, and
   the menu button goes last because it is the thing a thumb reaches for: on a
   phone the right edge is the near edge. Source order keeps the menu button
   early for the keyboard; `order` moves it visually, and it is safe here
   because the toggle is the only focusable item being moved and it stays
   adjacent to the sheet it controls. */
.dash-top__home {
  display: flex;
  align-items: center;
  text-decoration: none;
  order: -1;
}

.dash-top__home img { height: 28px; width: auto; }

@media (max-width: 1023px) {
  .dash-top .nav__toggle { order: 3; margin-left: var(--gp-dash-space-1); }
  .dash-top__actions { order: 2; margin-left: auto; gap: var(--gp-dash-space-1); }

  /* Smaller on a phone. Three 40px circles plus a menu button on a 390px
     screen leaves nothing for the mark. */
  /* THE NOTIFICATIONS BELL COMES OFF THE PHONE TOPBAR.

     Five controls in a 400px row, next to a wordmark and a menu button, and
     the bell is the one that goes. It is the only one of the five whose job
     is already done twice over: the sheet carries a Notifications link with
     its own unread count, and so does the rail the moment there is room for
     one. The theme toggle, the search and the avatar each exist in exactly
     one place.

     display:none and not visibility or opacity, so it leaves the flex row
     entirely rather than holding a 34px gap where a control used to be. It
     also leaves the tab order, which is correct: a keyboard user on a phone
     should not tab through a control they cannot see, and the same
     destination is two stops away in the menu.

     NOTHING IS LOST AND NOTHING IS HIDDEN. The unread count still reaches the
     reader, through the sheet, which is where every other section of this
     dashboard is reached from at this width. */
  /* .dash-top scopes it for SPECIFICITY, not for clarity. .dash-icon-btn sets
     display:inline-flex and is declared LATER in this file than this media
     query, so a bare .dash-top__notify ties at (0,1,0) and loses on source
     order. Two classes wins it outright and does not depend on where anybody
     later moves either block. */
  .dash-top .dash-top__notify { display: none; }

  .dash-top .dash-icon-btn { width: 34px; height: 34px; }
  .dash-top .dash-icon-btn .icon { width: 17px; height: 17px; }
  .dash-top .avatar { width: 28px; height: 28px; font-size: 11px; }
  .dash-top .dash-account { padding: 2px; }
}

@media (min-width: 1024px) {
  .dash-top__home { display: none; }
}

/* THE TOPBAR DOES NOT REPEAT THE PAGE TITLE.

   It did, and every screen then showed the same words twice, once in the bar
   and once as the h1 six pixels below it. The bar carries the customer's
   controls; the page carries its own name. Kept as a class because the admin
   console may want it on a screen whose h1 scrolls away, but it renders
   nothing here. */
.dash-top__title { display: none; }

.dash-top__actions {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: var(--gp-dash-space-2);
}

/* An icon control in the topbar: search, notifications, settings. 40px box,
   hairline ring, and a real accessible name on every one, because an icon
   alone has none and a screen reader would otherwise announce "button" three
   times in a row. */
.dash-icon-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--gp-dash-control-height);
  height: var(--gp-dash-control-height);
  border: 1px solid var(--gp-dash-hairline);
  border-radius: 50%;
  background: var(--gp-dash-panel);
  color: var(--gp-ink-muted);
}

.dash-icon-btn:hover {
  border-color: var(--gp-rule-strong);
  color: var(--gp-ink);
}

/* The unread dot. A dot at every width, a number only where there is room. */
.dash-icon-btn__dot {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--gp-danger-ink);
  border: 2px solid var(--gp-dash-panel);
}

/* The account control. Avatar alone at base, avatar plus name at lg. */
.dash-account {
  display: inline-flex;
  align-items: center;
  gap: var(--gp-dash-space-3);
  padding: var(--gp-dash-space-1);
  padding-right: var(--gp-dash-space-3);
  border: 1px solid var(--gp-dash-hairline);
  border-radius: var(--gp-radius-pill);
  background: var(--gp-dash-panel);
  text-decoration: none;
  color: var(--gp-ink);
}

.dash-account:hover { border-color: var(--gp-rule-strong); }

.dash-account__name {
  display: none;
  font-size: var(--gp-dash-text-meta);
  font-weight: var(--gp-fw-medium);
  white-space: nowrap;
}

@media (min-width: 1024px) {
  .dash-account__name { display: inline; }
}

/* ---------- The content column ---------- */

.dash-main {
  padding: var(--gp-dash-space-6) var(--gp-gutter) var(--gp-dash-space-8);
}

@media (min-width: 1024px) {
  .dash-main {
    padding: var(--gp-dash-space-7) var(--gp-dash-page-gutter)
             var(--gp-dash-space-8);
  }
}

.dash-main__inner {
  max-width: var(--gp-dash-content-max);
  margin-inline: auto;
}

.dash-head {
  margin-bottom: var(--gp-dash-space-6);
}

.dash-head h1 {
  font-size: var(--gp-dash-text-page);
  line-height: var(--gp-dash-leading-tight);
}

.dash-head__lead {
  margin-top: var(--gp-dash-space-2);
  font-size: var(--gp-dash-text-meta);
  color: var(--gp-ink-muted);
}

.dash-head__row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--gp-dash-space-4);
}


/* =============================================================================
   THE MOBILE RAIL

   Below 1024px the sheet IS the rail, not a different design that happens to
   hold the same links. Same Deep Forest ground, same lift on the current item,
   same marker. A customer who learns the rail on a laptop should recognise it
   on a phone, and two designs for one navigation is two things to maintain.

   IT IS WRITTEN AGAINST ROOT TOKENS, NOT --gp-dash-*, AND THAT IS NOT A
   SHORTCUT. The sheet is a SIBLING of .gp-dashboard rather than a descendant,
   so the dashboard token layer never reaches it: custom properties inherit
   down the tree, and a sibling is not down the tree. This first shipped using
   --gp-dash-rail and the sheet rendered fully transparent, with the nav
   floating over the page behind it. The rail colours are aliases of root
   tokens anyway, so nothing is lost by naming the root ones here.

   It scrolls vertically with NO VISIBLE SCROLLBAR: the bar is a desktop
   affordance, and on a sheet it sits over the content it is meant to reveal.
   Scrolling still works by touch, wheel and keyboard; only the bar is gone.
   ========================================================================== */

.sheet--rail {
  background: var(--gp-band);
  color: var(--gp-on-band);
  scrollbar-width: none;
  -ms-overflow-style: none;
}

.sheet--rail::-webkit-scrollbar { width: 0; height: 0; display: none; }

.sheet--rail .sheet__head {
  border-bottom-color: var(--gp-rule-on-band);
  min-height: 84px;
}

.sheet--rail .sheet__rule { background: var(--gp-rule-on-band); }

.sheet--rail .sheet__link {
  position: relative;
  gap: var(--gp-space-12);
  padding: var(--gp-space-12);
  margin-bottom: var(--gp-space-8);
  border-radius: var(--gp-radius);
  font-size: var(--gp-fs-body);
  font-weight: var(--gp-fw-regular);
  color: var(--gp-on-band-muted);
}

/* THE CLOSE BUTTON IN THIS SHEET.

   .nav__toggle is styled for the storefront masthead, which is a pale surface:
   a Pale Sage border with Charcoal ink. Dropped onto Deep Forest that is a
   bright box with a nearly invisible glyph inside it, which is the colour riot
   in the corner of the mobile menu. It is not a focus ring and it is not a
   pressed state, it is a light-theme control on a dark surface.

   Nothing is unstyled to fix it: the button keeps its shape and its 44px
   target and takes the band's own ink and hairline, the same pair every other
   control on this sheet already uses. */
.sheet--rail .sheet__head .nav__toggle {
  border-color: var(--gp-rule-on-band);
  color: var(--gp-on-band);
  background: transparent;
}

.sheet--rail .sheet__head .nav__toggle:hover {
  background: rgba(250, 249, 244, 0.08);
}

/* Rail Lift. The one literal in this block, because it is a value the root
   layer does not carry: #0D4A36, 9.72 on ivory, and 1.23 against Deep Forest
   itself, which is the point. It must be felt and not seen. */
.sheet--rail .sheet__link:hover,
.sheet--rail .sheet__link[aria-current='page'] {
  background: #0d4a36;
  color: var(--gp-on-band);
}

.sheet--rail .sheet__link[aria-current='page'] {
  font-weight: var(--gp-fw-semi);
}

.sheet--rail .sheet__link--secondary {
  font-size: var(--gp-fs-small);
  color: var(--gp-on-band-muted);
}

/* The same marker as the desktop rail, and for the same reason: it says WHERE
   YOU ARE, which is location and not state, and it is never the only signal. */
.sheet--rail .sheet__link[aria-current='page']::after {
  content: '';
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 20px;
  border-radius: 0 2px 2px 0;
  background: var(--gp-soft-leaf);
}

/* On the Deep Forest rail the same panel has to go the other way: --gp-surface
   is a light token and would drop a white card into the rail. It sinks into
   the band instead, using the band's own ink at low alpha, which is the same
   device --gp-rule-on-band already uses for a hairline there. */
.sheet--rail .sheet__sub {
  background: rgba(250, 249, 244, 0.06);
}

.sheet--rail .sheet__sub a { color: var(--gp-on-band-muted); }

.sheet--rail .sheet__sub a:hover {
  background: rgba(250, 249, 244, 0.10);
  color: var(--gp-on-band);
}

.sheet--rail .sheet__sub-count { color: var(--gp-on-band-muted); }

/* The auth card's actions and the line under them.

   base.css zeroes every default margin, so all spacing here is authored, and
   this rule was never written: on verify-otp and reset-password the Continue
   button, the resend row and the meta line under it sat flush against each
   other with zero pixels between. The fixture has the same gap, so this is a
   missing rule rather than something lost in the port.

   Not solved by adding .form-flow to the card: that would also re-space the
   fields, which already carry their own rhythm from .field. */
.auth-card .form-actions {
  margin-top: var(--gp-space-24);
}

.auth-card .form-actions + .t-meta,
.auth-card .form-actions + p {
  margin-top: var(--gp-space-12);
}
