/* ═══════════════════════════════════════════════════════════════════════════
   COPRODUCER.STUDIO — slate 01
   ═══════════════════════════════════════════════════════════════════════════

   Standalone. It does not load document.css: the long-form pages are a reading
   register and this is a single held frame, and sharing a stylesheet between
   them would mean every change to one is a risk to the other for the sake of
   about twenty shared declarations.

   THE EMPTINESS IS THE DESIGN. Nav at the top, everything else on the floor of
   the viewport, and the whole middle left alone. Anything added to fill it
   takes the confidence out, so nothing is.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  --face: 'Inter', -apple-system, 'Helvetica Neue', Helvetica, Arial, sans-serif;
  --data: 'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  /* Not pure white and not pure black. At this scale of type #000 on #fff rings
     on a bright display; a degree off each is the same contrast and none of the
     glare. */
  --paper: #fafaf8;
  --ink: #0a0a0a;
  --ink-2: #55555a;
  --presence: #2fbf5c;   /* available. The one knob the presence dot reads. */
  --ink-3: #98989a;
  --rule: #dcdcd8;
  --gutter: clamp(1.5rem, 4vw, 4.5rem);
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  /* min-height, not height: if a phone in landscape cannot fit the headline,
     the page must be allowed to scroll rather than clip it. */
  min-height: 100svh;
  display: grid;
  grid-template-rows: auto 1fr;
  padding: clamp(1.5rem, 3vh, 2.5rem) var(--gutter) clamp(2.5rem, 7vh, 5rem);
  background: var(--paper);
  color: var(--ink);
  font-family: var(--face);
  font-size: 1rem;
  line-height: 1.55;
  letter-spacing: -0.009em;
  -webkit-font-smoothing: antialiased;
}

svg { display: block; }

/* ── the nav ──────────────────────────────────────────────────────────────── */

/* THE GAP FLOORS ARE LOAD-BEARING AT 320px, and not for the reason it looks.
   The header is the widest thing on this page, so its min-content width sets the
   page's, and main, the h1 and every paragraph stretch to match. A fixed 2rem
   gap plus a third nav item made that 302px inside a 272px column, and the whole
   page scrolled sideways by 6px: the header was never the thing that visibly
   overflowed, the copy was.
   Both clamps now bottom out low enough that mark + gap + three items fit the
   narrowest phone, and open back up on anything wider. */
/* ── the header's two rows ────────────────────────────────────────────────
   .top is a COLUMN now. Each row is a full-width flex line of its own, which
   is the whole reason for the change: in one row, Login was laid out against
   the nav beside it, and putting it on its own edge would have needed an empty
   spacer element. In its own row it is laid out against the row.

   Each row keeps the height the header used to be, 1.3125rem, which is what the
   mark renders at: the SVG is 573.27 by 333.8, so at 2.25rem wide it is 21px
   tall. So the header is exactly twice what it was, and --head-h below says so
   rather than being measured again by hand. */
.top {
  display: flex;
  flex-direction: column;
}

.top-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: clamp(1rem, 4vw, 2rem);
  width: 100%;
  min-height: 1.3125rem;
}

/* Nothing to space against, so the single child goes to the end. */
.top-row--login { justify-content: flex-end; }

.top-mark { display: block; width: 2.25rem; color: var(--ink); }

.top-mark svg { width: 100%; height: auto; }

.top-nav {
  display: flex;
  gap: clamp(0.625rem, 3vw, 3rem);
  font-family: var(--data);
  font-size: 0.8125rem;
  color: var(--ink-2);
}

/* letter-spacing AND line-height ARE BOTH DECLARED HERE ON PURPOSE, and neither
   is redundant.

   letter-spacing: Chrome's UA stylesheet sets `letter-spacing: normal` on form
   controls. `font: inherit` does not fix it, because letter-spacing is not part
   of the font shorthand. So a <button> beside an <a> renders UNSPACED while the
   anchor is spaced: in monospace at 13px that is 0.144px per character, which is
   1.3px across "Workspace" and reads as one item sitting slightly off the others.

   line-height: buttons do not inherit it either; the UA sets `normal`. That put
   the button's text 0.56px lower than the anchors beside it.

   Both are sub-pixel and both are visible, because the eye reads a row of
   evenly-set words and the odd one out is the one it lands on. Declare them, and
   an <a> and a <button> in this nav become the same object. */
/* THE TYPOGRAPHY IS DECLARED HERE, NOT INHERITED FROM .top-nav, because Login
   is no longer inside .top-nav. It used to take font and colour from the nav via
   `font: inherit`; moved into its own row it inherited the BODY instead and came
   out 16px Inter next to 13px mono, 25px tall in a 21px row. An item that reads
   its type off its parent breaks the moment it is moved, and this one just was. */
.top-nav a,
.top-link {
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
  font-family: var(--data);
  font-size: 0.8125rem;
  font-weight: 400;
  letter-spacing: -0.011em;
  line-height: 1.55;
  color: var(--ink-2);
  text-decoration: none;
  /* .doc-nav-a has carried this from the start; this side did not, and it only
     showed once Login could hold a name instead of one short word. A long one
     broke onto a second line at 320px and made the header two rows tall. Nav
     items do not wrap; the length cap in slate.js is what keeps them in range. */
  white-space: nowrap;
  transition: color 160ms ease;
}

.top-nav a:hover,
.top-link:hover { color: var(--ink); }

/* SHOWN BY CSS, NOT BY SCRIPT, so it is right in the first painted frame. The
   markup keeps `hidden`, which is the correct state when there is no JavaScript
   at all and the honest default when nobody has signed in; the head script sets
   data-member and this rule beats the UA stylesheet's [hidden]. */
#enter { display: none; }

:root[data-member] #enter { display: inline; }

/* ── Login becomes the member's own name ──────────────────────────────────
   Signed out this reads "Login". Signed in it reads the display name from
   persons.display_name, fetched once at sign-in and kept.

   THE NAME ARRIVES AS A CSS VALUE, not as text, and that is forced by when it
   has to be right. The script that knows it runs in <head>, before this element
   is parsed, because doing it after would show "Login" for a frame and then the
   name, on every page load. So the head script sets --tk-login and this puts it
   in a ::after, and hides the literal word in the same breath. Exactly one of
   the two is ever showing.

   The word stays in the markup rather than being written by script: with no
   JavaScript at all, or before any of it runs, the button still says what it
   does. aria-label is set from the deferred script so a screen reader gets the
   name rather than generated content. */
:root[data-name] .login-word { display: none; }

/* inline-flex so the two generated boxes are flex items and align-items does
   the vertical centring: the dot's centre lands on the line box's centre, which
   is the middle of the name, not its baseline. */
:root[data-name] .login-link {
  display: inline-flex;
  align-items: center;
  gap: 0.45em;
}

:root[data-name] .login-link::before { content: var(--tk-login); }

/* THE PRESENCE DOT. ::after because ::before is already carrying the name and
   the dot goes to its right; generated boxes come out in that order.

   Sized in em, so it tracks the type rather than needing a second number kept
   in step with the first. 0.5em is 6.5px against the nav's 13px. (em, not rem:
   rem would hold the dot at one size while the text around it moved, which is
   the opposite of the point.)

   --presence is a single knob, defined on :root and read here, so whatever ends
   up deciding availability writes one property rather than reaching for this
   selector. */
:root[data-name] .login-link::after {
  content: "";
  flex: 0 0 auto;
  width: 0.5em;
  height: 0.5em;
  border-radius: 50%;
  background: var(--presence);
}

/* ── the phone menu ───────────────────────────────────────────────────────
   FOUR LINKS DO NOT FIT A PHONE. Measured: Coproducer, Manifesto, Login and
   Membership come to 290px of nav in the 272px a 320px screen leaves after the
   page gutters, so the whole page scrolled sideways by 46px. Three fitted, which
   is why this only became true when Membership was added, and it will get worse
   with every link after it.

   So below 30rem the links go behind one button. The button is the only thing
   that has to fit, whatever the nav grows to.

   The nav leaves the flow rather than pushing the page down: on the splash the
   whole point is one screen, and a menu that shoves the headline below the fold
   to show four words is worse than the overflow it fixes. */
.nav-toggle {
  display: none;
  padding: 0;
  border: none;
  background: none;
  color: inherit;
  cursor: pointer;
  font-family: var(--data); font-size: 0.8125rem; font-weight: 400;
  letter-spacing: -0.011em; line-height: 1.55;
  color: var(--ink-2);
}

.nav-toggle:hover { color: var(--ink); }

@media (max-width: 30rem) {
  /*  ABOVE THE TRAY. The tray tab is fixed at z-index 70 and the header
      creates its own stacking context, so the open nav panel's 60 was
      measured inside a header sitting below it: the tab floated over the
      menu. 80 puts the header, and everything it contains, on top. */
  .top { position: relative; z-index: 80; }

  .nav-toggle { display: block; }

  .top-nav {
    display: none;
    position: absolute; top: 100%; right: 0; left: 0; z-index: 60;
    flex-direction: column; align-items: flex-end;
    gap: 1.1rem;
    margin: 0 calc(-1 * var(--gutter));
    padding: 1.25rem var(--gutter) 1.5rem;
    background: var(--paper);
    border-bottom: 1px solid var(--rule);
  }

  /* Open is a fact about the document, not about the nav, so Escape, a link
     click and a resize past the breakpoint can all clear it from one place. */
  :root[data-nav="open"] .top-nav { display: flex; }
}

.door-say { margin: 0 0 1rem; font-size: 1rem; line-height: 1.5; color: var(--ink); }

.door-say--soft { margin-bottom: 0; font-size: 0.9375rem; color: var(--ink-2); }

/* THE EXPANSION. The dialog does not swap content, it grows: the fields appear
   under the copy that was already there, so the person can still read why they
   are being asked. A modal that replaces its own text on the first click makes
   somebody wonder whether they clicked the right thing. */
.creds {
  margin-top: 1.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
}

.creds[hidden] { display: none; }

/* WELCOME BACK. The face is what makes it read as "you" at a glance; "Not you?"
   is right under it for the next person at a shared machine. */
.creds-back { display: flex; flex-direction: column; align-items: center; gap: 0.35rem; margin: 0 0 1.25rem; text-align: center; }
.creds-back[hidden] { display: none; }
.creds-back-face { width: 4rem; height: 5rem; border-radius: 6px; object-fit: cover; background: var(--rule); }
.creds-back-face[hidden] { display: none; }
.creds-back-name { margin: 0.25rem 0 0; font-size: 1rem; color: var(--ink); }
.creds-back-alt { margin: 0; font-size: 0.9375rem; color: var(--ink-2); }

.creds .field:last-child { margin-bottom: 0; }

/* ── the floor ────────────────────────────────────────────────────────────
   Headline and paragraph share a baseline at the bottom of the screen. The
   right column starts past halfway, which is what makes the empty left of it
   read as deliberate rather than as a short line. */

.floor {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.72fr);
  align-items: end;
  gap: clamp(2rem, 5vw, 6rem);
  align-self: end;
  width: 100%;
}

.mega {
  margin: 0;
  font-size: clamp(2.75rem, 7.2vw, 7.5rem);
  font-weight: 700;
  line-height: 0.92;
  letter-spacing: -0.045em;
}

.say { max-width: 30rem; padding-bottom: 0.5rem; }

.say p { margin: 0 0 1.5rem; font-size: 1.0625rem; color: var(--ink-2); }

.say p:last-child { margin-bottom: 0; }

/* A BUTTON THAT LOOKS LIKE A LINK, and it has to be a button: it opens a
   dialog rather than going anywhere, and an <a href="#"> that opens a modal
   lies to everything from a screen reader to a middle click. */
.say-link {
  padding: 0;
  border: none;
  background: none;
  color: var(--ink);
  font: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

.say-link:hover { text-decoration-thickness: 2px; }

/* ── the sheet ────────────────────────────────────────────────────────────
   A native <dialog>. showModal() brings focus trapping, Escape, an inert page
   behind and a ::backdrop with nothing hand-written. */

.sheet {
  width: min(34rem, 100%);
  max-height: 88svh;
  padding: 0;
  border: 1px solid var(--ink);
  background: var(--paper);
  color: var(--ink);
  overflow: hidden;
}

.sheet::backdrop { background: rgba(10, 10, 10, 0.45); }

.wait { display: flex; flex-direction: column; max-height: 88svh; }

/* THE SAME TRAP .creds ALREADY FELL INTO, and it caught the form itself. The
   UA stylesheet's [hidden] { display: none } is a USER AGENT rule, so ANY
   author `display` beats it whatever the specificity. Setting form.hidden on
   submit therefore did nothing visible: the confirmation appeared underneath a
   form that was still standing, showing the person their own answers and an
   ADD ME button directly above the words "You're on the list."
   The attribute was true the whole time, which is why it read as correct from
   script and was only visible in a screenshot. */
.wait[hidden] { display: none; }

.sheet-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem clamp(1.25rem, 4vw, 2rem);
  border-bottom: 1px solid var(--ink);
}

.sheet-head { margin: 0; font-size: 1.25rem; font-weight: 600; letter-spacing: -0.03em; }

.sheet-x {
  width: 2.25rem; height: 2.25rem;
  padding: 0;
  border: none;
  background: none;
  color: var(--ink-2);
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  transition: color 160ms ease;
}

.sheet-x:hover { color: var(--ink); }

/* The only scrolling region, so the header and the button stay put while a
   thirty-seven item list is being worked through. */
.sheet-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: clamp(1.1rem, 4vw, 2rem);
}

/* ── fields ───────────────────────────────────────────────────────────────── */

/* TIGHT ON PURPOSE. Three labelled fields at the old spacing came to 261px
   before a single option had been shown, which on a phone pushed the folds
   under the fold. The label sits close to its own box, and the gap BETWEEN
   fields is what got cut, not the height of the controls: the input stays a
   45px tap target and the label stays legible. */
.field { display: grid; gap: 0.25rem; margin-bottom: 0.6rem; }


.field label {
  font-family: var(--data);
  font-size: 0.6875rem;
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-2);
}

.field input {
  padding: 0.75em 0.85em;
  border: 1px solid var(--rule);
  background: transparent;
  color: var(--ink);
  font-family: inherit;
  /* 16px minimum. Anything smaller and iOS Safari zooms the page on focus,
     which on a modal reads as the layout breaking. */
  font-size: 1rem;
  transition: border-color 160ms ease;
}

.field input:focus { outline: none; border-color: var(--ink); }

.field input[data-bad] { border-color: #d01505; }
/* A REQUIRED LIST THAT WAS LEFT EMPTY. The rule above the fold is the only
   border it has, so that is what turns red; border-color on the summary would
   have styled nothing, since the summary draws no border of its own. The count
   goes red too, because on a closed fold the word "Select" is the only part of
   the control a person is actually looking at. */
.fold[data-bad] { border-top-color: #d01505; }
.fold[data-bad] .fold-count { color: #d01505; }

/* ── the folds ────────────────────────────────────────────────────────────
   Closed by default. Three segments and thirty-seven departments is more form
   than a phone shows at once, and a modal that opens already scrolled past its
   own first field has lost the person before they start. */

/* No top margin. The rule is the separator, and a margin above it as well
   separates twice. */
.fold { margin-top: 0.4rem; border-top: 1px solid var(--rule); }

.fold summary {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  /* Still a comfortable row to hit: the summary is full width, so the target
     is the whole line rather than the text. */
  padding: 0.8rem 0;
  cursor: pointer;
  list-style: none;
}

/* Safari draws its own triangle through ::-webkit-details-marker, which
   list-style:none does not remove. */
.fold summary::-webkit-details-marker { display: none; }

.fold-name {
  font-family: var(--data);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-2);
}

/* The count IS the affordance: closed, it says whether anything is chosen, so
   the fold never has to be opened just to check. */
.fold-count {
  font-family: var(--data);
  font-size: 0.75rem;
  color: var(--ink-3);
}

.fold[open] .fold-count { color: var(--ink); }

.fold-count::after { content: ' +'; }

.fold[open] .fold-count::after { content: ' –'; }

.fold .chips { padding-bottom: 0.9rem; }

/* ── chips ────────────────────────────────────────────────────────────────
   A styled checkbox. The input stays in the DOM and focusable, only moved out
   of sight: display:none is an input the keyboard cannot reach. */

.chips { display: flex; flex-wrap: wrap; gap: 0.35rem; }

.chip { position: relative; display: inline-flex; cursor: pointer; }

.chip input { position: absolute; width: 1px; height: 1px; margin: 0; opacity: 0; }

.chip span {
  display: inline-block;
  padding: 0.5em 0.85em;
  border: 1px solid var(--rule);
  border-radius: 999px;
  font-family: var(--data);
  font-size: 0.75rem;
  color: var(--ink-2);
  transition: border-color 140ms ease, background 140ms ease, color 140ms ease;
}

.chip:hover span { border-color: var(--ink-3); color: var(--ink); }

.chip input:checked + span { border-color: var(--ink); background: var(--ink); color: var(--paper); }

/* The ring has to be drawn on the label, because the input it belongs to is
   invisible. Without this the set is untabbable in practice. */
.chip input:focus-visible + span { outline: 2px solid var(--ink); outline-offset: 2px; }

/* ── submit ───────────────────────────────────────────────────────────────── */

.sheet-foot {
  flex: 0 0 auto;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.65rem 1.25rem;
  padding: 1rem clamp(1.25rem, 4vw, 2rem);
  border-top: 1px solid var(--ink);
}

.btn {
  padding: 0.85em 1.6em;
  border: 1px solid var(--ink);
  background: var(--ink);
  color: var(--paper);
  cursor: pointer;
  font-family: var(--data);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  transition: background 160ms ease, color 160ms ease;
}

.btn:hover { background: transparent; color: var(--ink); }

.btn--quiet { margin-top: 1.5rem; border-color: var(--rule); background: transparent; color: var(--ink-2); }

.btn--quiet:hover { border-color: var(--ink); background: transparent; color: var(--ink); }

.wait-note {
  flex: 1 1 12rem;
  margin: 0;
  font-family: var(--data);
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--ink-3);
}

.wait-note[data-tone="bad"] { color: #d01505; }

/* ── the confirmation ─────────────────────────────────────────────────────── */

.done { padding: clamp(1.75rem, 5vw, 2.5rem); }

.done-head { margin: 0 0 0.4rem; font-size: 1.75rem; font-weight: 700; letter-spacing: -0.035em; }

.done-say { margin: 0; color: var(--ink-2); }

/* ── narrow ───────────────────────────────────────────────────────────────
   The floor stacks and the sheet becomes a bottom sheet, which is where a
   phone expects a modal to come from. */

@media (max-width: 46rem) {
  .floor { grid-template-columns: minmax(0, 1fr); gap: 2rem; }
  .mega { font-size: clamp(2.5rem, 12vw, 4rem); }
  .say { max-width: none; padding-bottom: 0; }

  .sheet {
    width: 100%;
    max-width: none;
    max-height: 92svh;
    margin: 0 0 0 auto;
    /* A dialog is centred by its own default margins; pinning it to the bottom
       needs the inset set explicitly rather than a transform, which would
       fight the browser's own centring on open. */
    position: fixed;
    inset: auto 0 0 0;
    border-width: 1px 0 0;
  }

  .wait { max-height: 92svh; }
  .sheet-foot .btn { flex: 1 1 100%; }
}

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
}

/* ── show the password ──────────────────────────────────────────────────────
   Sits inside the field rather than beside it, so it cannot be mistaken for a
   second control or wrap onto its own line at a narrow width. The input gets
   room on its right for the button rather than the button overlapping the text,
   because a masked field is exactly where you least want a character hidden
   under something.

   It is only styled here; without the script it does not exist, and the field
   is an ordinary password input. */
.field--pass { position: relative; }

.field--pass input { padding-right: 4.5rem; }

.peek {
  position: absolute;
  right: 0;
  bottom: 0.55rem;
  padding: 0.2rem 0.1rem;
  border: 0;
  background: none;
  color: var(--ink-3);
  cursor: pointer;
  font-family: var(--data);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.peek:hover,
.peek:focus-visible { color: var(--ink); }

/* ── the member menu, splash side ───────────────────────────────────────────
   Same panel as the document pages, in this stylesheet's own colours. Duplicated
   rather than shared for the same reason every other seam here is: two
   registers, two stylesheets, and a shared file for forty lines would couple
   them for no gain. */
.top-row--login { position: relative; }

.mem-menu {
  position: absolute;
  top: calc(100% + 0.5rem);
  right: 0;
  z-index: 20;
  display: flex;
  flex-direction: column;
  min-width: 11rem;
  border: 1px solid var(--ink);
  background: var(--paper);
}

.mem-menu[hidden] { display: none; }

.mem-item {
  display: block;
  padding: 0.7rem 1rem;
  border: 0;
  border-bottom: 1px solid var(--rule);
  background: none;
  color: var(--ink);
  cursor: pointer;
  font-family: var(--data);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  text-align: left;
  text-decoration: none;
}

.mem-item:last-child { border-bottom: 0; }

.mem-item:hover,
.mem-item:focus-visible { background: var(--ink); color: var(--paper); }

/* ── Coproducer in the nav is a door, not a link ────────────────────────────
   The twin of the rule in document.css. It only appears for a signed-in member,
   and when it does it is the one item that goes somewhere they cannot otherwise
   reach: a row of identical monospace words hides that. Filled, so it reads as
   open.

   THIS WAS MISSING HERE. The document pages had it and the splash did not, so
   the same button was a black door on twelve pages and a plain word on the one
   people actually land on. */
#enter {
  /*  IT MUST NOT MAKE THE ROW TALLER. At 0.45em of vertical padding the button
      was 34px against the 20px of the text links beside it, so the nav row grew
      by 14px the moment a member signed in and the name below it dropped with
      it: the whole header moved as a side effect of being recognised.

      The padding is horizontal only and the box is pinned to the line the links
      already occupy, so it reads as filled without changing anything around it.
      Height comes from line-height and the border, not from padding. */
  padding: 0 1.1em;
  line-height: 18px;
  border: 1px solid var(--ink);
  background: var(--ink);
  color: var(--paper);
  cursor: pointer;
  transition: background 160ms ease, color 160ms ease;
}

:root[data-member] #enter { display: inline-block; }

#enter:hover,
#enter:focus-visible { background: transparent; color: var(--ink); }

/* A link that is present and shut. Not hidden: somebody who cannot go in yet
   should see where they are going and be told why, rather than hunting for a
   button that was there yesterday. */
/* Only the nav item is inert. The two buttons become a live link to the
   account page when shut, so making every [data-shut] unclickable would kill
   the thing that replaced them. */
[data-shut] { opacity: 0.45; }
.mem-item[data-shut] { pointer-events: none; }

.mem-note {
  display: block;
  padding: 0.55rem 1rem 0.6rem;
  border-bottom: 1px solid var(--rule);
  font-family: var(--face);
  font-size: 0.585rem;
  line-height: 1.5;
  letter-spacing: 0;
  text-transform: none;
  color: #6b6b66;
}
.mem-note strong { font-weight: 600; color: var(--ink); }

/* The way out of a dialog that cannot let you in. Sits under the fields as a
   quiet alternative rather than beside Continue, where it would compete with
   the thing most people are about to press. */
.creds-alt { margin: 0.9rem 0 0; }

.creds-alt .linky,
.creds-back-alt .linky {
  padding: 0;
  background: none;
  border: 0;
  color: inherit;
  font: inherit;
  font-size: 0.8125rem;
  opacity: 0.7;
  text-decoration: underline;
  cursor: pointer;
}
.creds-alt .linky:hover,
.creds-alt .linky:focus-visible,
.creds-back-alt .linky:hover,
.creds-back-alt .linky:focus-visible { opacity: 1; }

/* ══ SIDE PANEL ═══════════════════════════════════════════════════════════
   Terms and privacy, slid in over the form rather than navigating away from
   it. See the long note in index.html for why it is a <dialog>: it has to sit
   in the top layer because the form it covers is already there.

   A DIALOG IS display:block WHEN OPEN AND display:none WHEN NOT, and giving it
   a display here would override the closed state and leave it on screen
   forever. So every layout rule is scoped to [open]. Same trap as an id
   selector beating [hidden], which this repo has hit before. */
.side {
  /* Pinned to the right edge, full height, rather than the centred box a
     modal dialog is by default. */
  inset: 0 0 0 auto;
  margin: 0 0 0 auto;
  width: min(32rem, 100%);
  max-width: 100%;
  height: 100dvh;
  max-height: 100dvh;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: #fff;
  color: #111;
  box-shadow: -1px 0 0 rgba(0, 0, 0, 0.12);
  overflow: hidden;
}
.side[open] { display: flex; flex-direction: column; }
.side::backdrop { background: rgba(17, 17, 17, 0.4); }

@media (prefers-reduced-motion: no-preference) {
  .side[open] { animation: side-in 0.22s cubic-bezier(0.22, 0.61, 0.36, 1); }
  @keyframes side-in { from { transform: translateX(100%); } }
}

/* THE CLOSE NEVER SCROLLS AWAY. flex:none on the head and the body taking the
   remaining height does this without position:sticky, which is one fewer thing
   to go wrong on iOS. The top padding clears a notch; the body's bottom
   padding clears the home indicator. */
.side-top {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: max(0.9rem, env(safe-area-inset-top)) 1rem 0.9rem;
  border-bottom: 1px solid #e8e8e8;
}
.side-head { margin: 0; font-size: 0.95rem; font-weight: 600; letter-spacing: 0; }
.side-x {
  flex: none;
  width: 2.25rem; height: 2.25rem;   /* a real touch target, not a glyph */
  display: grid; place-items: center;
  font-size: 1.25rem; line-height: 1;
  background: none; border: 0; color: inherit; cursor: pointer;
}
.side-x:hover { background: #f2f2f2; border-radius: 50%; }

/* overscroll-behavior: a flick at the end of the terms must not start dragging
   whatever is behind the panel, which is the thing that makes nested scrolling
   feel broken on a phone. */
.side-body {
  flex: 1 1 auto;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: 1.25rem 1rem calc(2rem + env(safe-area-inset-bottom));
}
.side-body .take { margin: 0 0 1.75rem; }
.side-body .opener { font-size: 1.1rem; margin: 0 0 0.5rem; }
.side-body p { font-size: 0.85rem; line-height: 1.55; }
.side-wait { color: #777; font-size: 0.8rem; }
