/* On --paper-warm: it used to be #F4F4F4, a quiet panel on a white page, and
   the warmth pass redefined it as the page ground. Every rule here that meant
   "slightly not the page" had quietly started meaning "exactly the page", which
   is worst on the two hover states: a hover that paints the ground gives no
   feedback at all. --paper-cream is the tier that kept its meaning. */

/* The signed-in area.
 *
 * Deliberately a different room from the public site: same typography and
 * colour, tighter rhythm, a persistent identity strip. Someone who is signed in
 * should be able to tell at a glance, without reading anything, that they are
 * looking at their own record rather than at marketing.
 *
 * Loaded after nbop.css and interactive.css, and reuses their tokens rather
 * than redefining any.
 */

/* ---------- portal chrome ---------- */

.portal-bar {
  background: var(--ink);
  color: #fff;
  border-bottom: 3px solid var(--navy);
}
.portal-bar .wrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  padding-top: 0.9rem;
  padding-bottom: 0.9rem;
  flex-wrap: wrap;
}
.portal-bar a { color: #fff; }
.portal-bar .mark {
  font-family: var(--ui);
  font-weight: 700;
  letter-spacing: 0.18em;
  font-size: 0.82rem;
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
}
.portal-bar .mark span {
  display: block;
  font-weight: 500;
  letter-spacing: 0.1em;
  font-size: 0.62rem;
  opacity: 0.62;
  margin-top: 0.15rem;
}
.portal-bar nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  gap: 1.4rem;
  flex-wrap: wrap;
}
.portal-bar nav a {
  font-family: var(--ui);
  font-size: 0.72rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  text-decoration: none;
  opacity: 0.72;
  padding-bottom: 0.2rem;
  border-bottom: 2px solid transparent;
}
.portal-bar nav a:hover { opacity: 1; }
.portal-bar nav a[aria-current="page"] { opacity: 1; border-bottom-color: #fff; }
.portal-bar .who {
  font-size: 0.78rem;
  opacity: 0.72;
  display: flex;
  align-items: center;
  gap: 0.9rem;
}
.portal-bar .who button {
  background: none;
  border: 1px solid rgba(255, 255, 255, 0.32);
  color: #fff;
  font: inherit;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.3rem 0.7rem;
  cursor: pointer;
}
.portal-bar .who button:hover { border-color: #fff; }

/* ---------- state ---------- */

.stage {
  border: 1px solid var(--rule);
  border-left: 3px solid var(--navy);
  padding: 1.5rem 1.7rem;
  margin: 0 0 2rem;
  background: var(--paper-cream);
}
.stage h2 { margin-top: 0; }
.stage p:last-child { margin-bottom: 0; }

.stage.good { border-left-color: #1d6b45; }
.stage.warn { border-left-color: #8a6412; }
.stage.stop { border-left-color: #8c2b2b; }

.steps { list-style: none; margin: 2rem 0; padding: 0; }
.steps li {
  display: flex;
  gap: 1rem;
  padding: 0.9rem 0;
  border-bottom: 1px solid var(--rule-soft);
  align-items: baseline;
}
.steps li:last-child { border-bottom: 0; }
.steps .n {
  font-family: var(--ui);
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  color: var(--ink-faint);
  min-width: 4.6rem;
  text-transform: uppercase;
  flex-shrink: 0;
}
.steps .t { flex: 1; }
.steps .t b { display: block; }
.steps .t small { color: var(--ink-faint); }
.steps li.done .t b { color: var(--ink-faint); text-decoration: line-through; }
.steps li.now { background: var(--paper-cream); margin: 0 -0.9rem; padding-left: 0.9rem; padding-right: 0.9rem; }

/* ---------- credential card ---------- */

.credcard {
  border: 1px solid var(--ink);
  padding: 1.8rem;
  margin: 1.5rem 0 2rem;
  background: var(--paper);
}
.credcard .cn {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 1.4rem;
  letter-spacing: 0.06em;
  color: var(--navy);
  display: block;
}
.credcard .rows {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 1rem 1.6rem;
  margin-top: 1.4rem;
  border-top: 1px solid var(--rule-soft);
  padding-top: 1.2rem;
}
.credcard .rows div span {
  display: block;
  font-family: var(--ui);
  font-size: 0.66rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 0.25rem;
}

/* ---------- endorsements ---------- */

.endorsements { display: grid; gap: 1.1rem; margin: 1.5rem 0 2rem; }
.endorsement {
  border: 1px solid var(--rule);
  padding: 1.2rem 1.4rem;
}
.endorsement.held { border-left: 3px solid var(--navy); background: var(--paper-cream); }
.endorsement h3 { margin: 0 0 0.4rem; }
.endorsement .asserts { margin: 0 0 0.8rem; }
.endorsement .gate {
  font-family: var(--ui);
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  color: var(--ink-faint);
  text-transform: uppercase;
}
.endorsement ul { margin: 0.6rem 0 0.9rem 1.1rem; padding: 0; }
.endorsement li { margin-bottom: 0.25rem; }

/* ---------- forms in the portal ---------- */

.pf { max-width: var(--measure); }
.pf label {
  display: block;
  font-family: var(--ui);
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 1.3rem 0 0.35rem;
}
.pf input[type="text"],
.pf input[type="email"],
.pf input[type="password"],
.pf select,
.pf textarea {
  width: 100%;
  font: inherit;
  font-size: 1rem;
  padding: 0.65rem 0.75rem;
  border: 1px solid var(--rule);
  background: var(--paper);
  color: var(--ink);
}
.pf input:focus, .pf select:focus, .pf textarea:focus {
  outline: 2px solid var(--navy);
  outline-offset: -1px;
}
.pf textarea { min-height: 7rem; resize: vertical; }
.pf .hint { font-size: 0.88rem; color: var(--ink-faint); margin: 0.35rem 0 0; }

.toggle {
  display: flex;
  gap: 0.8rem;
  align-items: flex-start;
  padding: 1rem 0;
  border-bottom: 1px solid var(--rule-soft);
}
.toggle:last-of-type { border-bottom: 0; }
.toggle input { margin-top: 0.25rem; flex-shrink: 0; width: 1.05rem; height: 1.05rem; }
.toggle .tx b { display: block; }
.toggle .tx small { color: var(--ink-faint); }

.msg { padding: 0.9rem 1.1rem; margin: 1.2rem 0; border: 1px solid var(--rule); }
.msg.err { border-color: #8c2b2b; color: #7a2323; background: #fdf7f7; }
.msg.ok { border-color: #1d6b45; color: #175637; background: #f5faf7; }

.rowbtns { display: flex; gap: 0.8rem; flex-wrap: wrap; margin-top: 1.6rem; }

.loading { color: var(--ink-faint); font-style: italic; }

@media (max-width: 40rem) {
  .portal-bar .wrap { align-items: flex-start; }
  .portal-bar nav ul { gap: 1rem; }
  .credcard { padding: 1.2rem; }
  .stage { padding: 1.2rem 1.1rem; }
  .steps li { flex-direction: column; gap: 0.2rem; }
  .steps .n { min-width: 0; }
}

/* --- portal alignment -----------------------------------------------------
   The portal is presentation only in this file. Nothing here touches ids,
   form names, endpoints or behaviour: Helm's functionality is untouched.

   These rules live in portal.css rather than nbop.css because portal.css
   loads last, so anything written in nbop.css loses to the portal's own
   older declarations. Putting them here means they land.

   Aim is that a signed-in page is visibly the same site as a public one:
   same banner, same 40px gutter, same Jost fields, same footer.
   ------------------------------------------------------------------------ */

main > .wrap { padding-inline: var(--gutter); max-width: calc(1212px + 2 * var(--gutter)); }

.pagehead > .wrap { padding-inline: var(--gutter); }
.pagehead .lede { color: #D6DEEB; max-width: 46ch; }

#portal, main > .wrap > .pf, main > .wrap > h2, main > .wrap > p {
  max-width: 45rem;
}
main > .wrap > h2 { margin-top: 3.5rem; margin-bottom: 1.25rem; }
#portal { padding-top: 60px; padding-bottom: 90px; }
main > .wrap > .pagehead + * { margin-top: 60px; }

.pf label {
  display: block;
  font-family: var(--ui);
  font-size: 12px;
  line-height: 1.4;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 1.75rem 0 .5rem;
}
.pf input, .pf select, .pf textarea {
  width: 100%;
  max-width: 45rem;
  font-family: var(--ui);
  font-size: 16px;
  line-height: 1.6;
  color: var(--ink);
  background: #FFFFFF;
  border: 1px solid #C2C9D3;
  border-radius: 2px;
  padding: .85rem 1rem;
}
.pf input:focus, .pf select:focus, .pf textarea:focus {
  outline: 2px solid var(--signal);
  outline-offset: 1px;
  border-color: var(--signal);
}
.pf .hint { font-size: 14px; line-height: 1.6; color: var(--ink-faint); margin: .5rem 0 0; }
.rowbtns { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 2.25rem; }
/* ---------- what we have committed to ----------
 *
 * The published service timelines, on the person's own record. Styled as a
 * plain ledger rather than a dashboard: these are dates we owe someone, and
 * dressing them up as widgets would make a missed one easier to skim past.
 */

.cases { margin: 2.4rem 0 0; }
.cases .muted { color: var(--ink-faint); font-size: 0.92rem; }

.cases-list { list-style: none; margin: 1.2rem 0 1.4rem; padding: 0; }

.cases-list li {
  padding: 1rem 0 1rem 0.9rem;
  border-bottom: 1px solid var(--rule-soft);
  border-left: 3px solid var(--rule);
}
.cases-list li:last-child { border-bottom: 0; }
.cases-list li.good { border-left-color: #1d6b45; }
.cases-list li.warn { border-left-color: #8a6412; }
.cases-list li.stop { border-left-color: #8c2b2b; }

.cases-list .top {
  display: flex;
  gap: 0.8rem;
  align-items: baseline;
  flex-wrap: wrap;
}
.cases-list .top b { font-size: 1.02rem; }

.cases-list .due { margin: 0.35rem 0 0.2rem; }
.cases-list small { display: block; color: var(--ink-faint); font-size: 0.82rem; }

.cases-list .pill {
  display: inline-block;
  font-family: var(--ui);
  font-size: 0.66rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  padding: 0.2rem 0.5rem;
  border: 1px solid var(--rule);
  color: var(--ink-faint);
  background: var(--paper-cream);
  white-space: nowrap;
}
.cases-list .pill.good { border-color: #1d6b45; color: #175637; background: #f5faf7; }
.cases-list .pill.warn { border-color: #8a6412; color: #6f500e; background: #fdf9f0; }
.cases-list .pill.stop { border-color: #8c2b2b; color: #7a2323; background: #fdf7f7; }

@media (max-width: 26rem) {
  .cases-list .top { gap: 0.5rem; }
  .cases-list .top b { font-size: 0.98rem; }
}

/* ---------- one class name, two components ----------
 *
 * nbop.css defines a .steps component for the public site's numbered process,
 * and the portal reuses the same class name for the route list. Same name,
 * different component, and nbop.css loads first so its numbered badge is
 * printed on top of the portal's own step label.
 *
 * Fixed here rather than by renaming because the class name is written into
 * portal.js as well, and a CSS rule cannot break behaviour. Scoped to #portal
 * so the public site's numbered process is untouched.
 */
#portal .steps li::before { content: none; }

/* ---------- the current page has to be readable ----------
 *
 * The public masthead marks the current page in navy, which is right on white
 * and unreadable here. Measured on the live portal bar: every other item sat
 * at 9.74:1 against the #161616 bar, and the current one, the single item whose
 * whole job is telling you where you are, sat at 1.70:1. WCAG AA wants 4.5.
 *
 * The bar's own rule set the underline and the opacity but never the colour,
 * so the public site's rule won by default. Setting the colour here takes it
 * to 15.9:1 and keeps the white underline doing the marking.
 */
.portal-bar nav a[aria-current="page"] {
  color: #fff;
  opacity: 1;
  border-bottom-color: #fff;
}

/* ---------- the rail ----------
 *
 * Modelled on Les Mills Connect: a narrow dark column that stays put, groups a
 * growing product into a few stable categories, and opens each into a labelled
 * panel. Adding continuing education to it is one entry rather than a redesign.
 *
 * Where this deliberately differs from theirs: every item carries a visible
 * caption as well as an icon, and the caption is a fragment of the full name
 * rather than a different word for it. Theirs is icon only with no accessible
 * name at all, which is a lovely thing to look at and impossible to use with a
 * screen reader.
 */

.portal-rail {
  position: fixed;
  top: 0; left: 0; bottom: 0;
  width: 5rem;
  background: var(--ink);
  color: #fff;
  display: flex;
  flex-direction: column;
  z-index: 50;
  overflow: visible;
}

.rail-brand {
  display: block;
  padding: 1rem 0.4rem 1.1rem;
  text-align: center;
  text-decoration: none;
  color: #fff;
  border-bottom: 1px solid rgba(255,255,255,0.14);
}
.rail-brand b {
  /* Stated because a global rule colours b as ink, which on this rail is the
   * background: the wordmark rendered #161616 on #161616 and was simply not
   * there. Third time a public site colour has landed in this dark room. The
   * sweep test below now checks every piece of text in the rail rather than
   * the one element someone remembered to look at. */
  color: #fff;
  display: block;
  font-family: var(--display);
  font-size: 0.92rem;
  letter-spacing: 0.09em;
}
.rail-brand span {
  display: block;
  margin-top: 0.15rem;
  font-family: var(--ui);
  font-size: 0.52rem;
  letter-spacing: 0.11em;
  text-transform: uppercase;
  opacity: 0.66;
}

.rail-list { list-style: none; margin: 0; padding: 0.5rem 0; }
.rail-bottom { margin-top: auto; padding-bottom: 0.7rem; }

.rail-item { position: relative; }

.rail-top {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.28rem;
  width: 100%;
  padding: 0.72rem 0.25rem;
  background: none;
  border: 0;
  color: #fff;
  opacity: 0.72;
  text-decoration: none;
  cursor: pointer;
  font: inherit;
}
.rail-top svg { width: 22px; height: 22px; display: block; }
.rail-top .rl {
  font-family: var(--ui);
  font-size: 0.53rem;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  line-height: 1.15;
  text-align: center;
}
.rail-top:hover, .rail-top:focus-visible { opacity: 1; }

/* The marker for where you are is a bar and full opacity, never a colour
 * change. A colour change is what put navy on near black and made the current
 * page the one item nobody could read.
 *
 * The colour is restated here anyway, and that is not belt and braces. The
 * public site sets a[aria-current="page"] to navy, and a plain .rail-top loses
 * to it on specificity, so the current item would have gone navy on near black
 * all over again. This exact bug has now appeared twice in the same stylesheet
 * from the same cause. Stating the colour on the state that a global rule also
 * targets is the thing that stops it appearing a third time. */
.rail-item.on > .rail-top { opacity: 1; box-shadow: inset 3px 0 0 #fff; color: #fff; }
.portal-rail .rail-top[aria-current="page"] { color: #fff; }
.portal-rail .rail-flyout a[aria-current="page"] { color: #fff; }
/* Dimmed enough to read as not yet available, not so dimmed that it fails the
 * contrast floor. 0.42 measured 4.09:1 against this background, just under the
 * 4.5 AA needs; 0.58 measures about 6.1. "Unavailable" is still information,
 * and information nobody can read is not a design choice. */
.rail-item.soon > .rail-top { opacity: 0.58; }

.rail-top:focus-visible { outline: 2px solid #fff; outline-offset: -3px; }

/* ---------- the panel that opens ---------- */

.rail-flyout {
  display: none;
  position: absolute;
  left: 100%;
  top: 0;
  min-width: 15rem;
  padding: 1rem 1.1rem 1.1rem;
  background: #1d2735;
  border-left: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 12px 34px rgba(0,0,0,0.34);
}
.rail-item.open > .rail-flyout { display: block; }

.rail-flyout h2 {
  margin: 0 0 0.6rem;
  font-family: var(--ui);
  font-size: 0.62rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: #fff;
  opacity: 0.66;
}
.rail-flyout ul { list-style: none; margin: 0; padding: 0; }
.rail-flyout li + li { margin-top: 0.1rem; }
.rail-flyout a {
  display: block;
  padding: 0.42rem 0;
  color: #fff;
  text-decoration: none;
  font-size: 0.94rem;
}
.rail-flyout a:hover, .rail-flyout a:focus-visible { text-decoration: underline; }
.rail-flyout a[aria-current="page"] { font-weight: 600; }
.rail-flyout a[aria-current="page"]::before { content: ""; }
.rail-flyout .soon {
  margin: 0;
  font-size: 0.86rem;
  line-height: 1.5;
  color: #fff;
  opacity: 0.78;
  max-width: 17rem;
}
.rail-flyout .who {
  margin: 0 0 0.7rem;
  font-size: 0.82rem;
  opacity: 0.72;
  word-break: break-all;
}
.rail-flyout .btn.small { font-size: 0.72rem; padding: 0.45rem 0.9rem; }

/* ---------- everything else moves over ---------- */

body.has-rail main,
body.has-rail footer { margin-left: 5rem; }

/* ---------- narrow screens ----------
 *
 * The history is worth keeping, because the first answer was defensible and
 * still wrong. It laid the rail down into a horizontal strip on the argument
 * that a person should be able to see there is a Registry and a Handbook
 * without first discovering a hamburger. On a real handset that strip ran off
 * the right edge with nothing to say that it moved, and the items that fell
 * off the end were Console and Account, which are the two the board itself
 * reaches for most. A control nobody can see is worse than a control you have
 * to open, because the second one at least admits what it is.
 *
 * What is here now is a bar: the mark and the wordmark at the left, a three
 * line button at the right, and the menu itself in a drawer that comes in from
 * that side. The drawer is at the bottom of this file.
 */
@media (max-width: 48rem) {
  .portal-rail {
    position: sticky;
    top: 0;
    left: auto;
    right: auto;
    bottom: auto;
    width: auto;
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    border-bottom: 1px solid rgba(255,255,255,0.14);
  }

  /* The icon rail is exactly what the drawer replaces, so it goes. */
  .portal-rail .rail-list,
  .portal-rail .rail-bottom { display: none; }

  /* Grid rather than flex so the mark can sit beside two stacked lines of type
   * without a wrapper element around them. */
  .portal-rail .rail-brand {
    border-bottom: 0;
    display: grid;
    grid-template-columns: auto 1fr;
    column-gap: 0.5rem;
    align-items: center;
    padding: 0.5rem 0.85rem;
    text-align: left;
    min-width: 0;
  }
  .portal-rail .rail-brand .mark {
    grid-column: 1;
    grid-row: 1 / 3;
    margin-bottom: 0;
  }
  .portal-rail .rail-brand b { grid-column: 2; grid-row: 1; font-size: 0.92rem; }
  /* 0.52rem is 8.3px. That is the size this stylesheet has already been caught
   * shipping once, and it is not readable on a phone at arm's length whatever
   * it says. 0.7rem is 11.2px, which is the floor the sweep holds everything
   * else to. */
  .portal-rail .rail-brand span {
    grid-column: 2;
    grid-row: 2;
    display: block;
    font-size: 0.7rem;
    letter-spacing: 0.08em;
  }

  body.has-rail main,
  body.has-rail footer { margin-left: 0; }
}

/* ---------- the rail owns its own layout ----------
 *
 * The rail is a <nav>, and the public site styles nav ul as a wrapping flex
 * row for the masthead. That rule reached in here and did real damage: every
 * item became a shrink to fit flex item 43px wide instead of 80, wrapped one
 * per line because two would not fit, and each icon ended up centred on its
 * own caption's width rather than on the rail. Measured spread between icon
 * centres was 21.3px, which is exactly as ragged as it looked.
 *
 * Scoped by width rather than written once, because the narrow layout genuinely
 * does want a flex row and a blanket rule here would have silently undone it.
 */

@media (min-width: 48.0625rem) {
  .portal-rail .rail-list {
    display: block;
    flex-wrap: nowrap;
    gap: 0;
  }
  .portal-rail .rail-item { width: 100%; }
  .portal-rail .rail-top { width: 100%; }
}


/* The wordmark belongs at the top left corner, not floating in the middle of
 * an 80px column. */
.portal-rail .rail-brand {
  text-align: left;
  padding: 0.85rem 0.65rem 0.9rem;
}
.portal-rail .rail-brand .mark {
  display: block;
  width: 22px;
  height: 22px;
  margin-bottom: 0.3rem;
  color: #fff;
}

/* ---------- the rail captions were 8.5px ----------
 *
 * My own doing, and the worst text on the site: 0.53rem uppercase, which is
 * 8.5px. The whole reason the captions exist is that Les Mills ships an icon
 * only rail nobody can read, so shipping captions nobody can read would have
 * been the same failure wearing a different hat.
 *
 * Sentence case rather than the house uppercase, because uppercase plus
 * letter-spacing made "Certification" 99px wide and it has to fit a rail. The
 * rail widens from 5rem to 6.5rem to carry it at a readable 11.5px.
 */
.portal-rail { width: 6.5rem; }
body.has-rail main,
body.has-rail footer { margin-left: 6.5rem; }
.portal-rail .rail-top .rl {
  font-size: 0.72rem;
  text-transform: none;
  letter-spacing: 0.01em;
}
@media (max-width: 48rem) {
  .portal-rail { width: auto; }
  body.has-rail main,
  body.has-rail footer { margin-left: 0; }
}


/* ================= the phone menu =================
 *
 * Everything below here is invisible above 48rem. The button is display:none
 * outside the narrow media query, so the drawer cannot be opened at a width it
 * was not built for, and the script closes it if the window grows anyway.
 *
 * Every colour in here is stated rather than inherited. That is not caution
 * for its own sake: this stylesheet has now had public site rules reach into
 * the dark portal five separate times, and twice the result was white text
 * turning near black on a near black panel, which nothing catches by eye. The
 * ancestor selectors are longer than they need to be for the same reason.
 */

.rail-burger {
  display: none;
  align-items: center;
  gap: 0.5rem;
  padding: 0.7rem 0.95rem;
  background: none;
  border: 0;
  color: #fff;
  font: inherit;
  cursor: pointer;
  /* 44px on both axes. The handbook commits this board to accommodations, and
   * a menu button a thumb cannot reliably hit is the smallest possible way to
   * not mean it. */
  min-width: 44px;
  min-height: 44px;
}
/* Shown only under the width it exists for, and written here rather than up in
 * the narrow block because that block comes first in the file and a bare
 * .rail-burger later would have quietly outranked it. */
@media (max-width: 48rem) { .rail-burger { display: flex; } }
.rail-burger .bars { display: block; width: 20px; }
.rail-burger .bars i {
  display: block;
  height: 2px;
  background: currentColor;
  border-radius: 1px;
}
.rail-burger .bars i + i { margin-top: 4px; }
.rail-burger .bl {
  font-family: var(--ui);
  /* 12px. At 0.68rem it measured 10.9px and the sweep was right to fail it by
   * a tenth of a pixel: a floor you round down to is not a floor. */
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #fff;
}
.rail-burger:focus-visible { outline: 2px solid #fff; outline-offset: -3px; }

.rail-scrim {
  position: fixed;
  top: 0; right: 0; bottom: 0; left: 0;
  background: rgba(0,0,0,0.55);
  z-index: 60;
}

.rail-drawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: 20rem;
  max-width: 86vw;
  z-index: 70;
  display: flex;
  flex-direction: column;
  background: #1d2735;
  color: #fff;
  border-left: 1px solid rgba(255,255,255,0.14);
  box-shadow: -14px 0 40px rgba(0,0,0,0.42);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}

/* [hidden] carries an attribute selector, so it outranks the display above no
 * matter which order a build tool ends up putting them in. */
.rail-drawer[hidden], .rail-scrim[hidden] { display: none; }

@media (min-width: 48.0625rem) {
  .rail-drawer, .rail-scrim { display: none; }
}

/* The page behind stops moving. Without this the drawer scrolls the document
 * under it the moment it reaches its own end. */
html.drawer-open, html.drawer-open body { overflow: hidden; }

@media (prefers-reduced-motion: no-preference) {
  .rail-drawer:not([hidden]) { animation: nbop-drawer-in 180ms ease-out; }
  .rail-scrim:not([hidden]) { animation: nbop-scrim-in 180ms ease-out; }
}
@keyframes nbop-drawer-in { from { transform: translateX(100%); } to { transform: none; } }
@keyframes nbop-scrim-in { from { opacity: 0; } to { opacity: 1; } }

.rail-drawer .drawer-head {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.55rem 0.5rem 0.55rem 1.1rem;
  background: #1d2735;
  border-bottom: 1px solid rgba(255,255,255,0.14);
}
/* Stated because "strong, b" sets colour by name near the top of the public
 * stylesheet, and the last time that reached a dark panel the wordmark went
 * #161616 on #161616 and stayed invisible until a sweep measured it. */
.rail-drawer .drawer-head b {
  color: #fff;
  font-size: 0.95rem;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.rail-drawer .drawer-close {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 0.6rem;
  background: none;
  border: 0;
  color: #fff;
  cursor: pointer;
}
.rail-drawer .drawer-close svg { width: 22px; height: 22px; display: block; }
.rail-drawer .drawer-close:focus-visible { outline: 2px solid #fff; outline-offset: -3px; }

.rail-drawer .drawer-nav { padding: 0.35rem 0 0.6rem; }
.rail-drawer .drawer-group { padding: 0.55rem 1.1rem 0.65rem; }
.rail-drawer .drawer-group + .drawer-group { border-top: 1px solid rgba(255,255,255,0.09); }
.rail-drawer .drawer-group h2,
.rail-drawer .drawer-account h2 {
  margin: 0 0 0.3rem;
  font-family: var(--ui);
  font-size: 0.62rem;
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: #fff;
  opacity: 0.66;
}
.rail-drawer ul { list-style: none; margin: 0; padding: 0; display: block; }
.rail-drawer li { margin: 0; padding: 0; }

.rail-drawer .drawer-link {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 44px;
  padding: 0.55rem 0;
  color: #fff;
  text-decoration: none;
  font-size: 0.98rem;
  line-height: 1.3;
  border-bottom: 0;
}
.rail-drawer .drawer-link svg { width: 20px; height: 20px; flex: 0 0 auto; }
.rail-drawer .drawer-link:hover,
.rail-drawer .drawer-link:focus-visible { text-decoration: underline; }
.rail-drawer .drawer-link:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

/* Where you are is weight and a bar, never a colour change. A colour change is
 * exactly what put navy on near black and made the current page the one line
 * on the screen nobody could read. */
.rail-drawer .drawer-link[aria-current="page"] {
  color: #fff;
  font-weight: 600;
  box-shadow: inset 3px 0 0 #fff;
  padding-left: 0.7rem;
}

.rail-drawer p.soon {
  margin: 0;
  font-size: 0.86rem;
  line-height: 1.5;
  color: #fff;
  /* 0.78 measures about 8:1 here. Unavailable is still information, and
   * information nobody can read is not a design choice. */
  opacity: 0.78;
}

.rail-drawer .drawer-account {
  margin-top: auto;
  padding: 0.85rem 1.1rem 1.15rem;
  border-top: 1px solid rgba(255,255,255,0.14);
}
.rail-drawer .drawer-account .who {
  margin: 0 0 0.7rem;
  font-size: 0.82rem;
  color: #fff;
  opacity: 0.72;
  word-break: break-all;
}
/* inline-flex rather than the inherited inline-block so the 44px floor centres
 * the label instead of hanging it at the top. 42px is not a rounding error to
 * a thumb. */
.rail-drawer .btn.small {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  font-size: 0.72rem;
  padding: 0.45rem 1.1rem;
}

/* --- the content column, anchored rather than adrift -----------------------
   #portal was capped at a 45rem reading measure and then centred by .wrap in
   whatever space the rail left over. On a wide screen that put 348px of empty
   gutter on each side of a 720px column, so the content floated in the middle
   right with no relationship to the rail anchoring the left edge.

   A reading measure is right for prose and wrong for a record: the cards,
   step lists and tables on these pages are components rather than paragraphs,
   and they were being squeezed into a column sized for sentences.

   So the container is anchored left and allowed to breathe. Prose keeps its
   own measure: the existing rule caps main > .wrap > p at 45rem and still
   applies, so paragraphs do not stretch to the new width.
--------------------------------------------------------------------------- */

#portal {
  max-width: 60rem;
  margin-left: 0;
  margin-right: auto;
}

/* Below the width where the rail becomes a drawer there is no rail to anchor
   to, so the column goes back to being centred. */
@media (max-width: 48rem) {
  #portal { margin-left: auto; }
}


/* The member footer carries one nav column rather than three, so the grid that
   was built for four tracks would stretch it across the page. See memberFooter
   in portal.js for why the marketing columns are not shown to somebody who has
   already signed up. */
footer .foot-grid.foot-grid-member {
  /* Two columns sized to their contents and packed to the left, rather than
     two fractions spread across a width that was measured for four. Fractional
     tracks would leave the same gap the removed columns used to fill, which
     reads as something missing rather than as something removed. */
  grid-template-columns: minmax(0, 26rem) minmax(0, 15rem);
  justify-content: start;
  column-gap: clamp(3rem, 8vw, 7rem);
}
@media (max-width: 62rem) {
  footer .foot-grid.foot-grid-member { grid-template-columns: minmax(0, 1fr); }
}

/* --- the doors --------------------------------------------------------------
   Status first, then three destinations a member can walk through today. The
   reference is the dashboard pattern of the big training platforms, taken for
   its structure and not its dress: their cards are photographs with imperative
   captions, these are the same typographic cards the public site uses,
   because a standards body does not need a model mid burpee to make a course
   worth opening.
--------------------------------------------------------------------------- */

.doors {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1rem;
  margin: 1rem 0 2.4rem;
}
.door {
  display: block;
  border: 1px solid var(--rule);
  border-top: 3px solid var(--navy);
  background: var(--paper);
  padding: 1.15rem 1.2rem 1.25rem;
  text-decoration: none;
  color: inherit;
  transition: border-color .13s ease, transform .13s ease, box-shadow .13s ease;
}
.door:hover, .door:focus-visible {
  border-top-color: var(--signal);
  transform: translateY(-2px);
  box-shadow: 0 10px 22px rgba(13, 30, 59, .10);
}
.door .door-k {
  display: block;
  font-family: var(--ui);
  font-size: .64rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: .45rem;
}
.door b {
  display: block;
  font-family: var(--display);
  font-weight: 600;
  font-size: 1.18rem;
  line-height: 1.25;
  margin-bottom: .4rem;
}
.door p {
  margin: 0;
  font-size: .86rem;
  line-height: 1.55;
  color: var(--ink-soft);
}

/* --- the flyout, matched to the public dropdowns ----------------------------
   The rail panels had drifted a long way from the public nav: a 240 by 166
   pixel navy slab for two links, in fifteen pixel uppercase inherited from the
   rail buttons, with a rhythm nothing else on the site has. The public
   dropdowns are compact paper panels with a signal top border and quiet rows,
   so the signed in menus now use exactly that grammar. One menu system,
   whichever side of the sign in you are on.

   Everything is stated explicitly rather than inherited, because inheritance
   from the rail is what produced the drift in the first place: the rail
   buttons are uppercase letterspaced Jost, and the panel links caught all
   three properties on the way down.
--------------------------------------------------------------------------- */

.portal-rail .rail-flyout {
  min-width: 13.5rem;
  padding: 0.45rem 0 0.55rem;
  background: var(--paper);
  border: 1px solid var(--rule);
  border-top: 2px solid var(--signal);
  border-left: 0;
  box-shadow: 0 12px 28px rgba(13, 30, 59, 0.18);
}

.portal-rail .rail-flyout h2 {
  margin: 0;
  padding: 0.45rem 1rem 0.35rem;
  font-family: var(--ui);
  font-size: 0.62rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-faint);
  opacity: 1;
}

/* The global nav rule lays every nav ul out as a flex row with a 1.75rem
   gap, which is right for the masthead and wrong here: it was the last
   source of the giant rows. Stated, not inherited, like everything else
   in this panel. */
.portal-rail .rail-flyout ul { display: block; gap: 0; }

.portal-rail .rail-flyout a {
  display: block;
  padding: 0.5rem 1rem;
  font-family: var(--ui);
  font-size: 0.74rem;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1.35;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}
.portal-rail .rail-flyout a:hover,
.portal-rail .rail-flyout a:focus-visible {
  background: var(--paper-cream);
  color: var(--signal);
  text-decoration: none;
}
.portal-rail .rail-flyout a[aria-current="page"] { color: var(--signal); font-weight: 600; }

.portal-rail .rail-flyout .who {
  padding: 0.45rem 1rem 0.2rem;
  margin: 0;
  color: var(--ink-soft);
  opacity: 1;
}
.portal-rail .rail-flyout .soon {
  padding: 0.2rem 1rem 0.45rem;
  color: var(--ink-soft);
  opacity: 1;
  max-width: 17rem;
}
.portal-rail .rail-flyout .btn.small { margin: 0.35rem 1rem 0.5rem; }

/* The account sits at the bottom of the rail, so a panel anchored to its top
   edge runs off the bottom of the screen: the email was clipped and the sign
   out button was below the viewport entirely, which for a while made signing
   out a scroll puzzle. Anchored to the bottom edge it grows upward instead.
   Wider than the other panels because its longest line is an email address,
   and an address broken across lines reads as two addresses. */
.portal-rail .rail-account > .rail-flyout {
  top: auto;
  bottom: 0;
  min-width: 19rem;
}
.portal-rail .rail-flyout .who { word-break: normal; overflow-wrap: anywhere; }

/* --- the sitting runner ----------------------------------------------------
   Question cards for the assessment page. Deliberately spare: a candidate
   under a clock needs the stem, the options, and nothing that competes with
   them. The timer bar is sticky because scrolling away from a clock does not
   stop it, and the page being honest about that beats a surprise.
--------------------------------------------------------------------------- */

.exam-bar {
  position: sticky; top: 0; z-index: 20;
  background: var(--paper);
  border-bottom: 2px solid var(--signal);
  padding: 0.7rem 0.2rem;
  margin-bottom: 1.4rem;
  font-family: var(--ui);
}
.exam-bar b { font-variant-numeric: tabular-nums; }
.exam-save { margin-left: 1.2rem; color: var(--ink-faint); font-size: 0.85rem; }

.exam-q {
  border: 1px solid var(--rule);
  background: var(--paper);
  padding: 1.2rem 1.3rem;
  margin: 0 0 1.2rem;
}
.exam-stem { font-weight: 500; line-height: 1.6; margin: 0 0 0.9rem; }
.exam-opt {
  display: flex; gap: 0.6rem; align-items: baseline;
  padding: 0.45rem 0.4rem; margin: 0; cursor: pointer;
  border-radius: 2px;
}
.exam-opt:hover { background: var(--paper-cream); }
.exam-opt input { flex: 0 0 auto; }
.exam-q textarea {
  width: 100%; font: inherit; font-size: 0.95rem; line-height: 1.6;
  border: 1px solid var(--rule); padding: 0.7rem; resize: vertical;
}

/* === the directory profile editor =========================================
   Two ideas carry the layout.

   The verified block sits at the top, read only, on the cream tier rather than
   on white, because the holder should be looking at both halves of their
   public page while they edit one of them. If the editor showed only the part
   they write, the separation the public page depends on would exist only on
   the public page.

   The controls are wide, quiet and unranked. There is no completion meter and
   no required field marker anywhere, so nothing in the visual language implies
   a fuller profile is a better one.
--------------------------------------------------------------------------- */

.pf-verified {
  background: var(--paper-cream);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--navy);
  border-radius: var(--r-md);
  padding: 1.25rem 1.4rem;
  margin: 1.75rem 0 2.25rem;
}
.pf-verified h2 { margin-top: 0; font-size: 1.05rem; }
.pf-verified h2::before { content: none; }
.pf-vrows {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: .8rem 1.4rem; margin: 1rem 0 0;
}
.pf-vrows dt {
  font-size: .68rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink-faint); margin: 0 0 .15rem;
}
.pf-vrows dd {
  margin: 0; font-family: ui-monospace, Menlo, Consolas, monospace;
  font-size: .92rem; color: var(--ink);
}

.pf-form { margin-top: 1rem; }
.pf-form h2 { margin-top: 2.5rem; }
.pf-field { margin: 0 0 1.6rem; max-width: var(--measure); }

/* The hint sits inside the label so it is read as part of the label rather
   than orphaned beside it, which means both halves have to be blocks or they
   run together into one sentence. */
.pf-field > label.field { display: block; margin: 0 0 .4rem; max-width: none; }
.pf-field > label.field > span {
  display: block; font-weight: 600; color: var(--ink); margin: 0 0 .15rem;
}
.pf-field > label.field > .hint {
  display: block; font-weight: 400; font-size: .86rem; line-height: 1.5;
  color: var(--ink-faint); margin: 0 0 .5rem;
}
.pf-field input[type="text"],
.pf-field textarea,
.pf-field select {
  width: 100%; font: inherit; font-size: .97rem; line-height: 1.55;
  border: 1px solid var(--rule); border-radius: var(--r-sm);
  padding: .6rem .7rem; background: var(--paper); color: var(--ink);
}
.pf-field textarea { resize: vertical; }
.pf-field input:focus-visible,
.pf-field textarea:focus-visible,
.pf-field select:focus-visible { outline: 2px solid var(--signal); outline-offset: 1px; }

/* The count states the limit rather than enforcing it, so going over is
   visible and recoverable instead of silently truncated on paste. */
.pf-count {
  margin: .3rem 0 0; font-size: .8rem; color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}
.pf-count.over { color: #7a2323; font-weight: 600; }

/* ---- capped multiple choice ---- */

.pf-chips, .pf-ranked {
  border: 1px solid var(--rule); border-radius: var(--r-md);
  background: var(--paper); padding: 1.1rem 1.25rem; margin: 0 0 1.6rem;
}
.pf-chips legend, .pf-ranked legend {
  font-family: var(--display); font-size: 1.02rem; font-weight: 600;
  padding: 0 .4rem; color: var(--ink);
}
.pf-chips .hint, .pf-ranked .hint { margin: 0 0 .9rem; max-width: var(--measure); }

.pf-chiplist { display: flex; flex-wrap: wrap; gap: .5rem; }
.pf-chip {
  display: inline-flex; align-items: center; gap: .45rem;
  border: 1px solid var(--rule); border-radius: var(--r-pill);
  padding: .4rem .8rem; cursor: pointer; font-size: .92rem;
  background: var(--paper); color: var(--ink-soft);
}
.pf-chip:hover { border-color: var(--ink-faint); color: var(--ink); }
.pf-chip.is-on { background: var(--paper-cream); border-color: var(--navy); color: var(--ink); font-weight: 600; }
.pf-chip.is-off { opacity: .45; cursor: not-allowed; }
.pf-chip input { margin: 0; }
.pf-chip:focus-within { outline: 2px solid var(--signal); outline-offset: 2px; }

.pf-cap { margin: .8rem 0 0; font-size: .82rem; color: var(--ink-faint); }

/* ---- the ordered pick ---- */

.pf-picked { list-style: none; margin: 0 0 1rem; padding: 0; counter-reset: none; }
.pf-picked li {
  display: flex; align-items: center; gap: .75rem; flex-wrap: wrap;
  padding: .6rem .7rem; margin: 0 0 .5rem;
  background: var(--paper-cream); border: 1px solid var(--rule);
  border-radius: var(--r-sm);
}
.pf-rank {
  flex: 0 0 auto; width: 1.6rem; height: 1.6rem; border-radius: 50%;
  background: var(--navy); color: #FFFFFF; font-size: .78rem; font-weight: 600;
  display: inline-flex; align-items: center; justify-content: center;
  font-variant-numeric: tabular-nums;
}
.pf-picked-name { flex: 1 1 12rem; font-weight: 600; }
.pf-rank-btns { display: flex; gap: .4rem; flex-wrap: wrap; }
.pf-none {
  display: block; padding: .6rem 0; color: var(--ink-faint); font-style: italic;
  background: transparent; border: 0;
}
.pf-pool-label {
  margin: 0 0 .5rem; font-size: .68rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink-faint);
}
.pf-pool { display: flex; flex-wrap: wrap; gap: .5rem; }
.pf-add, .pf-mini {
  font: inherit; cursor: pointer; background: var(--paper);
  border: 1px solid var(--rule); border-radius: var(--r-pill);
  color: var(--ink-soft);
}
.pf-add { padding: .4rem .8rem; font-size: .92rem; }
.pf-mini { padding: .22rem .6rem; font-size: .78rem; }
.pf-add:hover, .pf-mini:hover { border-color: var(--navy); color: var(--ink); }
.pf-add:focus-visible, .pf-mini:focus-visible { outline: 2px solid var(--signal); outline-offset: 2px; }
.pf-add:disabled { opacity: .4; cursor: not-allowed; }

.pf-never { margin-top: 3rem; }
.pf-never ul { max-width: var(--measure); }
.pf-never li { margin: 0 0 .6rem; color: var(--ink-soft); line-height: 1.6; }

@media (max-width: 34rem) {
  .pf-picked li { align-items: flex-start; }
  .pf-rank-btns { width: 100%; }
}
