/* ────────────────────────────────────────────────────────────────────────────────────────
   Praesia — product surface.

   Palette is taken from the existing landing (.src/landings/praesia.php) so the product does
   not look like a different company from the page that sold it: cream #F9F4EA ground, near
   black #1C1C1C ink, brand green #69C629.

   ⚠️ The brand green fails WCAG AA as TEXT on cream (3.15:1). It is used here for marks,
   rules and fills only; --praesia-accent-text is the darkened variant (4.7:1) for anything
   the reader has to read. Measure contrast, do not eyeball it.

   ⚠️ Every custom property is declared on .praesia-shell, so any markup rendered outside that
   wrapper resolves every var() to nothing. See the sandwich invariant in _nav.php.
   ──────────────────────────────────────────────────────────────────────────────────────── */

.praesia-shell {
  --praesia-ground:       #F9F4EA;
  --praesia-ground-2:     #F2ECDD;
  --praesia-ink:          #1C1C1C;
  --praesia-ink-2:        #4B5563;
  --praesia-ink-3:        #6B7280;
  --praesia-accent:       #69C629;   /* brand green — marks, rules, fills */
  --praesia-accent-text:  #3D7A15;   /* darkened — anything that must be read */
  --praesia-accent-wash:  rgba(105, 198, 41, .12);
  --praesia-panel:        #1C1C1C;
  --praesia-panel-ink:    #F9F4EA;
  --praesia-rule:         rgba(28, 28, 28, .14);
  --praesia-warn:         #8A5A00;
  --praesia-alert:        #9B2C1E;

  --praesia-measure: 66ch;

  background: var(--praesia-ground);
  color: var(--praesia-ink);
  font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* ── topbar ──────────────────────────────────────────────────────────────────────────── */
.praesia-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding: 14px clamp(16px, 5vw, 48px);
  background: var(--praesia-panel);
  color: var(--praesia-panel-ink);
}

.praesia-mark {
  font-weight: 700;
  letter-spacing: -.01em;
  font-size: 1.25rem;
  color: var(--praesia-panel-ink);
  text-decoration: none;
}
.praesia-mark .dot { color: var(--praesia-accent); }

.praesia-topnav {
  display: flex;
  align-items: center;
  gap: clamp(12px, 3vw, 26px);
  font-size: .74rem;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
}
.praesia-topnav a {
  color: var(--praesia-panel-ink);
  text-decoration: none;
}
.praesia-topnav a:hover { color: var(--praesia-accent); }
.praesia-topnav-quiet { opacity: .7; }

/* ── layout ──────────────────────────────────────────────────────────────────────────── */
.praesia-main {
  flex: 1;
  width: 100%;
  max-width: 1080px;
  margin: 0 auto;
  padding: clamp(32px, 6vw, 72px) clamp(16px, 5vw, 48px) 80px;
  display: flex;
  flex-direction: column;
  gap: 34px;
}

.praesia-eyebrow {
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--praesia-accent-text);
  margin: 0 0 10px;
}

.praesia-h1 {
  font-size: clamp(1.9rem, 5vw, 3rem);
  font-weight: 700;
  line-height: 1.06;
  letter-spacing: -.025em;
  text-wrap: balance;
  margin: 0 0 14px;
}
.praesia-h2 { font-size: clamp(1.3rem, 3vw, 1.7rem); font-weight: 700; letter-spacing: -.02em; margin: 0 0 14px; }
.praesia-h3 { font-size: 1.05rem; font-weight: 700; margin: 0 0 8px; }

.praesia-lede {
  font-size: 1.05rem;
  color: var(--praesia-ink-2);
  max-width: var(--praesia-measure);
  line-height: 1.6;
  margin: 0 0 20px;
}

.praesia-fineprint {
  font-size: .84rem;
  color: var(--praesia-ink-3);
  max-width: var(--praesia-measure);
  line-height: 1.55;
  margin: 10px 0 0;
}

/* ── buttons ─────────────────────────────────────────────────────────────────────────── */
.praesia-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  background: var(--praesia-accent);
  color: var(--praesia-ink);
  font-weight: 700;
  font-size: .78rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  text-decoration: none;
  border: 0;
  border-radius: 999px;
  padding: 11px 22px;
  cursor: pointer;
  transition: background .2s ease;
}
.praesia-btn:hover { background: #5AB321; color: var(--praesia-ink); }
.praesia-btn-sm { padding: 7px 16px; font-size: .68rem; }
.praesia-btn-lg { padding: 14px 30px; font-size: .82rem; }

.praesia-btn:focus-visible,
.praesia-link:focus-visible,
.praesia-google:focus-visible,
.praesia-topnav a:focus-visible,
.praesia-mark:focus-visible {
  outline: 3px solid var(--praesia-accent-text);
  outline-offset: 3px;
}

.praesia-link {
  color: var(--praesia-accent-text);
  font-weight: 600;
  font-size: .9rem;
  text-decoration: none;
  border-bottom: 1px solid var(--praesia-accent);
  align-self: flex-start;
}
.praesia-link:hover { color: var(--praesia-ink); }

/* ── the door ────────────────────────────────────────────────────────────────────────── */
.praesia-door { max-width: 620px; }

.praesia-google {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  background: #FFFFFF;
  color: #1C1C1C;
  font-weight: 600;
  font-size: .98rem;
  text-decoration: none;
  border: 1px solid var(--praesia-rule);
  border-radius: 999px;
  padding: 13px 26px;
  box-shadow: 0 1px 2px rgba(28, 28, 28, .08);
}
.praesia-google:hover { border-color: var(--praesia-ink); color: #1C1C1C; }
.praesia-google-glyph { display: inline-flex; }

.praesia-doorpoints {
  list-style: none;
  margin: 34px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
  max-width: var(--praesia-measure);
}
.praesia-doorpoints li {
  position: relative;
  padding-left: 22px;
  color: var(--praesia-ink-2);
  font-size: .94rem;
  line-height: 1.55;
}
.praesia-doorpoints li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .55em;
  width: 10px;
  height: 2px;
  background: var(--praesia-accent);
}

.praesia-alert {
  background: rgba(155, 44, 30, .09);
  border-left: 3px solid var(--praesia-alert);
  color: var(--praesia-alert);
  padding: 14px 18px;
  border-radius: 0 3px 3px 0;
  max-width: var(--praesia-measure);
}

/* ── credential wall ─────────────────────────────────────────────────────────────────── */
.praesia-wall { list-style: none; margin: 0; padding: 0; display: grid; gap: 16px; }

.praesia-cred {
  background: #FFFFFF;
  border: 1px solid var(--praesia-rule);
  border-left: 4px solid var(--praesia-accent);
  border-radius: 4px;
  padding: 20px 22px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
/* State is carried in FORM as well as words: the rail colour is readable at a glance, which
   is what an expiry countdown has to be if it is going to bring anyone back. */
.praesia-cred-expiring { border-left-color: var(--praesia-warn); }
.praesia-cred-expired,
.praesia-cred-revoked  { border-left-color: var(--praesia-alert); opacity: .78; }

.praesia-cred-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}
.praesia-cred-name { font-size: 1.1rem; font-weight: 700; margin: 0; letter-spacing: -.01em; }

.praesia-chip {
  font-size: .66rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  padding: 4px 10px;
  border-radius: 3px;
  white-space: nowrap;
}
.praesia-chip-valid    { background: var(--praesia-accent-wash); color: var(--praesia-accent-text); }
.praesia-chip-expiring { background: rgba(138, 90, 0, .12);      color: var(--praesia-warn); }
.praesia-chip-expired,
.praesia-chip-revoked  { background: rgba(155, 44, 30, .10);     color: var(--praesia-alert); }

.praesia-cred-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 30px;
  margin: 0;
}
.praesia-cred-meta dt {
  font-size: .66rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--praesia-ink-3);
  margin: 0 0 2px;
}
.praesia-cred-meta dd {
  margin: 0;
  font-size: .95rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
/* A value that is deliberately absent rather than measured — today, every percentile.
   Lighter and not bold, so it reads as "we have not established this" rather than as a
   figure; --praesia-ink-2 is the body-text grey, so it stays legible rather than decorative. */
.praesia-cred-meta dd.praesia-muted {
  font-weight: 500;
  color: var(--praesia-ink-2);
}

/* ── The public Passport ───────────────────────────────────────────────────────────────────
   Claiming a handle, publishing, and the per-credential visibility switch. */

.praesia-publicprofile {
  margin-top: 46px;
  padding-top: 26px;
  border-top: 1px solid var(--praesia-rule);
}

.praesia-handleform {
  margin-top: 14px;
}

.praesia-fieldlabel {
  display: block;
  font-size: .66rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--praesia-ink-3);
  margin-bottom: 6px;
}

/* The prefix sits INSIDE the row rather than in placeholder text: a handle is an address, and
   showing the whole address while it is being chosen is what makes "cannot be changed later"
   land before the claim rather than after it. */
.praesia-handlerow {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.praesia-handleprefix {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .92rem;
  color: var(--praesia-ink-2);
}

.praesia-input {
  flex: 1 1 200px;
  min-width: 0;
  padding: 10px 12px;
  font: inherit;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  color: var(--praesia-ink);
  background: var(--praesia-ground);
  border: 1px solid var(--praesia-rule);
  border-radius: 6px;
}

.praesia-input:focus-visible {
  outline: 2px solid var(--praesia-accent-text);
  outline-offset: 1px;
}

/* Refusals are read by someone who has just been stopped, so they get the warning colour and
   real weight rather than fine print. --praesia-warn is already AA on the cream ground. */
.praesia-formerror {
  margin: 12px 0;
  padding: 10px 14px;
  border-left: 3px solid var(--praesia-warn);
  background: var(--praesia-ground-2);
  color: var(--praesia-warn);
  font-weight: 600;
}

/* A form that must look like the link it replaces: hiding a credential is a POST because it
   changes state, but it reads as one more quiet action on the card. */
.praesia-visform {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 10px;
  margin-top: 6px;
}

.praesia-linkbtn {
  padding: 0;
  font: inherit;
  font-size: .86rem;
  font-weight: 600;
  color: var(--praesia-accent-text);
  background: none;
  border: 0;
  border-bottom: 1px solid transparent;
  cursor: pointer;
}

.praesia-linkbtn:hover,
.praesia-linkbtn:focus-visible {
  border-bottom-color: currentColor;
}

/* ── The map ───────────────────────────────────────────────────────────────────────────────
   The status bar: XP, streak, credentials held, league position and the practice-to-proof gap.
   The map itself is further down, under "The map: a technology tree". */

.praesia-statusbar {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 34px;
  margin: 20px 0 26px;
  padding: 14px 18px;
  background: var(--praesia-ground-2);
  border-radius: 8px;
}

.praesia-statusnum {
  font-family: 'Poppins', sans-serif;
  font-weight: 700;
  font-size: 1.5rem;
  font-variant-numeric: tabular-nums;
  margin-right: 7px;
}

.praesia-statuslab {
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--praesia-ink-3);
}

/* The practice-to-proof gap gets the warning colour — it is the one number on the bar that is
   asking for something rather than reporting an achievement. */
.praesia-status-gap .praesia-statusnum,
.praesia-status-gap .praesia-statuslab {
  color: var(--praesia-warn);
}

/* The league cell is the only one on the bar that goes anywhere, and it must look it — a number
   that is quietly a link is a link nobody presses. No underline on the figure, which would read
   as a strikethrough on a position. */
.praesia-statuslink {
  color: inherit;
  text-decoration: none;
  border-bottom: 2px solid var(--praesia-accent);
  padding-bottom: 1px;
}

.praesia-statuslink:hover .praesia-statuslab,
.praesia-statuslink:focus-visible .praesia-statuslab {
  color: var(--praesia-accent-text);
}

.praesia-statuslink:focus-visible {
  outline: 2px solid var(--praesia-accent-text);
  outline-offset: 3px;
}

/* ── Clash ───────────────────────────────────────────────────────────────────────────────── */

.praesia-clashmodes {
  list-style: none;
  margin: 22px 0;
  padding: 0;
  display: grid;
  /* auto-fit with a minimum, so three modes sit in a row on a desktop and stack on a phone
     without a breakpoint. The daily loop is thumb-sized; this page is read on both. */
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 16px;
}

.praesia-clashmode {
  display: flex;
  padding: 18px 20px;
  background: var(--praesia-ground-2);
  border-radius: 8px;
}

.praesia-clashmode form {
  display: flex;
  flex-direction: column;
  /* The button sits on the baseline of the tallest card rather than under its own text, so three
     cards with different-length hints still line their actions up. */
  gap: 10px;
  flex: 1;
}

.praesia-clashmode .praesia-fineprint {
  flex: 1;
  margin: 0;
}

.praesia-clashmode .praesia-btn {
  align-self: flex-start;
}

/* The reveal. Decisions are engine JSON, so they can be long and have no spaces to break on —
   scrolling the cell beats stretching the table past the viewport. */
.praesia-clashdecision {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .8rem;
  max-width: 26ch;
  overflow-x: auto;
  white-space: nowrap;
}

/* ── The week's quests ───────────────────────────────────────────────────────────────────── */

.praesia-quests {
  margin: 0 0 30px;
}

.praesia-questlist {
  list-style: none;
  margin: 12px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.praesia-quest {
  display: grid;
  /* The name takes what is left; the two figures sit in fixed columns so every row's numbers line
     up down the list. A flex row with space-between would ragged them against the name lengths. */
  grid-template-columns: 1fr auto auto;
  gap: 14px;
  align-items: baseline;
  padding: 10px 14px;
  background: var(--praesia-ground-2);
  border-left: 4px solid transparent;
  border-radius: 4px;
}

/* Done is marked by the accent EDGE and the figure, never by striking the name out: a struck-out
   line reads as cancelled, and the opposite happened. */
.praesia-quest.is-done {
  border-left-color: var(--praesia-accent);
}

.praesia-questprogress {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
}

.praesia-quest.is-done .praesia-questprogress {
  color: var(--praesia-accent-text);
}

.praesia-questxp {
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--praesia-ink-3);
  font-variant-numeric: tabular-nums;
}

.praesia-nextstep {
  margin: 0 0 30px;
  padding: 18px 22px;
  border-left: 4px solid var(--praesia-accent);
  background: var(--praesia-ground-2);
}

.praesia-nextstep .praesia-h2 {
  margin: 4px 0 6px;
}
.praesia-nextstep .praesia-link {
  display: inline-block;
  margin-top: 6px;
}

.praesia-map { margin: 34px 0; }
.praesia-map-head .praesia-fineprint { margin: -6px 0 20px; }

/* ── The map: a technology tree ────────────────────────────────────────────────────────────
   Columns are levels (I, II, III — the ages of a tech tree), rows are competencies, bands are
   families. The previous drawing was one vertical rule per family with a dot per station: every
   row looked the same whether earned, a run away or never issuable, and nothing said Level 2
   follows Level 1. Here progression is a direction on the page, and each node has room to say
   what it certifies, how far along it is and what to do next.

   Colour is never the only carrier. Every state is also a word (.praesia-station-state), every
   progress figure is also text; the ring, fill and dash reinforce. Nothing here needs JS.

   Geometry lives in three custom properties so the connectors and the badges agree by
   construction: --praesia-gap (the column gap, which is also the connector's length),
   --praesia-badge (the badge diameter — connectors meet the badge's centre line) and
   --praesia-node-pad (the card padding the badge sits inside). */

.praesia-tree {
  --praesia-gap:      28px;
  --praesia-badge:    38px;
  --praesia-node-pad: 16px;
}

/* The age ruler. One per map, so every band reads against the same header. */
.praesia-ages {
  display: grid;
  grid-template-columns: repeat(var(--praesia-cols, 3), minmax(0, 1fr));
  gap: var(--praesia-gap);
  padding: 0 0 12px;
  border-bottom: 2px solid var(--praesia-ink);
}

.praesia-age {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}

.praesia-age-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--praesia-ink);
  color: var(--praesia-panel-ink);
  font-weight: 700;
  font-size: .78rem;
  letter-spacing: .04em;
}

.praesia-age-name {
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--praesia-ink-2);
}

/* ── bands (families) ── */
.praesia-zone { padding: 22px 0 8px; }
.praesia-zone + .praesia-zone { border-top: 1px solid var(--praesia-rule); }

.praesia-zone-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 16px;
  margin-bottom: 4px;
}

.praesia-zone-name {
  margin: 0;
  font-size: .76rem;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--praesia-accent-text);
}

.praesia-zone-progress {
  font-size: .78rem;
  font-weight: 600;
  color: var(--praesia-ink-2);
  font-variant-numeric: tabular-nums;
}

.praesia-zone-bar {
  flex: 1 1 120px;
  max-width: 220px;
  height: 6px;
  border-radius: 3px;
  background: var(--praesia-rule);
  overflow: hidden;
}
.praesia-zone-bar > span {
  display: block;
  height: 100%;
  border-radius: 3px;
  background: var(--praesia-accent);
}

/* ── rows (competencies) ── */
.praesia-branch { padding: 16px 0 18px; }
.praesia-branch + .praesia-branch { border-top: 1px dashed var(--praesia-rule); }

.praesia-branch-name {
  margin: 0 0 14px;
  font-size: 1.02rem;
  font-weight: 700;
  letter-spacing: -.01em;
}

.praesia-stations {
  list-style: none;
  margin: 0;
  /* Room above the cards for the "next step" tag, which hangs 11px over the card it marks. */
  padding: 8px 0 0;
  display: grid;
  grid-template-columns: repeat(var(--praesia-cols, 3), minmax(0, 1fr));
  gap: 18px var(--praesia-gap);
  align-items: stretch;
}

/* A node sits in its level's column; an undefined level leaves its column empty. */
.praesia-station {
  position: relative;
  grid-column: var(--praesia-col, auto);
  display: flex;
  flex-direction: column;
}

/* The connector back to the previous DEFINED level, at the height of the badge's centre.
   --praesia-span is how many columns back it sits: 1 is the neighbour, 2 crosses an undefined
   level in between, so the line is (span - 1) card widths plus span gaps long. Grey until the
   level before is held, then the accent — a row reads as far as the learner has come. */
.praesia-station.has-prev::before {
  content: "";
  position: absolute;
  right: 100%;
  top: calc(var(--praesia-node-pad) + var(--praesia-badge) / 2 - 1px);
  height: 2px;
  width: calc((var(--praesia-span, 1) - 1) * 100% + var(--praesia-span, 1) * var(--praesia-gap));
  background: var(--praesia-rule);
}
.praesia-station.has-prev.prev-earned::before { background: var(--praesia-accent); }

/* ── the node ── */
.praesia-node {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: var(--praesia-node-pad);
  background: #FFFFFF;
  border: 1px solid var(--praesia-rule);
  border-radius: 6px;
}

.praesia-station-earned .praesia-node {
  border-color: var(--praesia-accent);
  background: linear-gradient(var(--praesia-accent-wash), var(--praesia-accent-wash)) #FFFFFF;
}

/* Never issuable: an outline, not a card — there is nothing inside it to do. */
.praesia-station-unavailable .praesia-node {
  background: transparent;
  border-style: dashed;
}

/* The proposed next step is ringed AND labelled: the ring is what the eye lands on, the label
   is what a screen reader lands on. */
.praesia-station.is-next .praesia-node {
  outline: 2px solid var(--praesia-accent);
  outline-offset: 2px;
}
.praesia-node-next {
  position: absolute;
  z-index: 1;
  top: -11px;
  left: 14px;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--praesia-ink);
  color: var(--praesia-panel-ink);
  font-size: .6rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  white-space: nowrap;
}

.praesia-node-head {
  display: flex;
  align-items: flex-start;
  gap: 12px;
}

.praesia-node-titles { min-width: 0; }

/* The badge: level numeral in a ring. Filled = held. Accent ring = reachable now. Solid ring =
   in progress. Dashed = untouched. Amber/red = lapsed/revoked. Grey with a lock = never. */
.praesia-node-badge {
  position: relative;
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--praesia-badge);
  height: var(--praesia-badge);
  border-radius: 50%;
  border: 2px solid var(--praesia-ink-3);
  background: var(--praesia-ground);
  color: var(--praesia-ink);
  font-weight: 700;
  font-size: .84rem;
  letter-spacing: .04em;
}

.praesia-node-mark {
  position: absolute;
  right: -7px;
  bottom: -5px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--praesia-ink);
  color: var(--praesia-panel-ink);
  border: 2px solid #FFFFFF;
}
.praesia-node-mark svg { width: 11px; height: 11px; }

.praesia-station-earned .praesia-node-badge {
  background: var(--praesia-accent);
  border-color: var(--praesia-accent);
}
.praesia-station-ready .praesia-node-badge {
  border-color: var(--praesia-accent);
  box-shadow: 0 0 0 4px var(--praesia-accent-wash);
  animation: praesia-halo 2.2s ease-in-out infinite;
}
.praesia-station-in_progress .praesia-node-badge { border-color: var(--praesia-ink); }
.praesia-station-open .praesia-node-badge        { border-style: dashed; }
.praesia-station-expired .praesia-node-badge     { border-color: var(--praesia-warn);  color: var(--praesia-warn); }
.praesia-station-revoked .praesia-node-badge     { border-color: var(--praesia-alert); color: var(--praesia-alert); }
.praesia-station-unavailable .praesia-node-badge {
  border-color: var(--praesia-rule);
  background: var(--praesia-ground-2);
  color: var(--praesia-ink-3);
}
.praesia-station-unavailable .praesia-node-mark { background: var(--praesia-ink-3); }

@keyframes praesia-halo {
  0%, 100% { box-shadow: 0 0 0 3px var(--praesia-accent-wash); }
  50%      { box-shadow: 0 0 0 8px var(--praesia-accent-wash); }
}

.praesia-node-eyebrow {
  margin: 3px 0 3px;
  font-size: .64rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--praesia-ink-3);
}

.praesia-station-state {
  display: inline-block;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--praesia-ink-2);
}
.praesia-station-earned .praesia-station-state,
.praesia-station-ready .praesia-station-state   { color: var(--praesia-accent-text); }
.praesia-station-expired .praesia-station-state { color: var(--praesia-warn); }
.praesia-station-revoked .praesia-station-state { color: var(--praesia-alert); }
.praesia-station-unavailable .praesia-station-state { color: var(--praesia-ink-3); }

.praesia-node-criteria {
  margin: 0;
  font-size: .88rem;
  line-height: 1.5;
  color: var(--praesia-ink-2);
}

/* Progress: one pip per qualifying run the rule asks for, filled as they land. The figures
   underneath say the same thing in words, on both axes of the rule. */
.praesia-node-progress {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: auto;
}

.praesia-pips {
  display: inline-flex;
  gap: 5px;
}
.praesia-pips i {
  display: block;
  width: 24px;
  height: 8px;
  border-radius: 2px;
  background: var(--praesia-rule);
}
.praesia-pips i.is-on { background: var(--praesia-accent); }
.praesia-station-expired .praesia-pips i.is-on { background: var(--praesia-warn); }

.praesia-node-meta {
  margin: 0;
  font-size: .76rem;
  line-height: 1.5;
  color: var(--praesia-ink-3);
  font-variant-numeric: tabular-nums;
}

.praesia-node-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 16px;
}
.praesia-node-actions .praesia-link { font-size: .84rem; }

.praesia-station-interchange {
  position: relative;
  display: block;
  padding-left: 20px;
  font-size: .78rem;
  line-height: 1.45;
  color: var(--praesia-ink-2);
}
.praesia-station-interchange::before {
  content: "\21C4";
  position: absolute;
  left: 0;
  top: -1px;
  font-weight: 700;
  color: var(--praesia-accent-text);
}

/* ── legend ── */
.praesia-legend {
  list-style: none;
  margin: 20px 0 0;
  padding: 14px 0 0;
  border-top: 1px solid var(--praesia-rule);
  display: flex;
  flex-wrap: wrap;
  gap: 8px 22px;
  font-size: .76rem;
  font-weight: 600;
  color: var(--praesia-ink-2);
}
.praesia-legend li {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.praesia-node-badge-sm {
  --praesia-badge: 16px;
  width: 16px;
  height: 16px;
  font-size: 0;
}
.praesia-legend .praesia-node-badge {
  animation: none;
  box-shadow: none;
}

/* On a phone the columns stack: each row becomes a vertical chain, the connector turns to run
   from the badge above down to this one, and the age ruler goes — every node names its own
   level in its eyebrow. */
@media (max-width: 720px) {
  .praesia-ages { display: none; }

  .praesia-stations {
    grid-template-columns: 1fr;
    gap: 22px;
  }
  .praesia-station { grid-column: auto; }

  .praesia-station.has-prev::before {
    top: auto;
    right: auto;
    bottom: 100%;
    left: calc(var(--praesia-node-pad) + var(--praesia-badge) / 2 - 1px);
    width: 2px;
    height: 22px;
  }
}

/* ── Rankings ──────────────────────────────────────────────────────────────────────────────
   A rating is never shown as a bare number where there is room for its interval: 1620 ± 300 and
   1620 ± 40 are different claims and only one belongs on a board. */

.praesia-rankpicker {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 22px 0;
}

.praesia-rankpick {
  padding: 6px 13px;
  font-size: .88rem;
  font-weight: 600;
  color: var(--praesia-ink-2);
  background: var(--praesia-ground-2);
  border-radius: 999px;
  text-decoration: none;
}

.praesia-rankpick.is-on {
  color: var(--praesia-panel-ink);
  background: var(--praesia-panel);
}

.praesia-rankpick:focus-visible {
  outline: 2px solid var(--praesia-accent-text);
  outline-offset: 2px;
}

.praesia-standing {
  margin: 26px 0;
  padding: 16px 20px;
  border-left: 4px solid var(--praesia-accent);
  background: var(--praesia-ground-2);
}

.praesia-standingnum {
  margin: 4px 0;
  font-family: 'Poppins', sans-serif;
  font-weight: 700;
  font-size: 2.1rem;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}

/* The interval, deliberately quieter than the number but never absent. */
.praesia-standinginterval {
  font-size: .95rem;
  font-weight: 500;
  color: var(--praesia-ink-2);
  margin-left: 8px;
}

/* Wide content scrolls in its own container so the page body never scrolls sideways. */
.praesia-tablewrap {
  overflow-x: auto;
  margin: 22px 0;
}

.praesia-board {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}

.praesia-board th {
  text-align: left;
  padding: 9px 12px;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--praesia-ink-3);
  border-bottom: 2px solid var(--praesia-rule);
  white-space: nowrap;
}

.praesia-board td {
  padding: 9px 12px;
  border-bottom: 1px solid var(--praesia-rule);
}

.praesia-board tr.is-me td {
  background: var(--praesia-accent-wash);
  font-weight: 600;
}

/* ── The weekly league ───────────────────────────────────────────────────────────────────── */

/* The two boundaries, drawn as a left edge on the row rather than as a fill.
   A fill would fight the .is-me wash — a learner sitting in the promotion zone is in BOTH
   states at once, and that is the most important row on the board. An edge and a background
   compose; two backgrounds do not, and one of them would silently win. */
.praesia-leaguerow td:first-child {
  border-left: 4px solid transparent;
  padding-left: 8px;
}

.praesia-leaguerow.is-promote td:first-child {
  border-left-color: var(--praesia-accent);
}

.praesia-leaguerow.is-relegate td:first-child {
  border-left-color: var(--praesia-alert);
}

/* Colour is not the only carrier: the zone is also stated in words above the table, because a
   reader who cannot distinguish green from red must still be able to see where the line is. */
.praesia-league .praesia-fineprint {
  max-width: var(--praesia-measure);
}

/* ── The public profile page ─────────────────────────────────────────────────────────────── */

.praesia-profile-head {
  margin-bottom: 32px;
}

.praesia-profile-foot {
  margin-top: 32px;
  padding-top: 16px;
  border-top: 1px solid var(--praesia-rule);
  font-size: .9rem;
  color: var(--praesia-ink-2);
}

.praesia-profile-empty {
  padding: 40px 0;
}

.praesia-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .82rem;
  letter-spacing: .06em;
  color: var(--praesia-ink-3);
}

/* ── cards ───────────────────────────────────────────────────────────────────────────── */
.praesia-cards {
  display: grid;
  gap: 16px;
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
}
.praesia-cards-wide { grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr)); }

.praesia-card {
  background: #FFFFFF;
  border: 1px solid var(--praesia-rule);
  border-radius: 4px;
  padding: 22px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.praesia-card h3, .praesia-card-title { font-size: 1.05rem; font-weight: 700; margin: 0; letter-spacing: -.01em; }
.praesia-card p, .praesia-card-promise { font-size: .93rem; color: var(--praesia-ink-2); margin: 0; line-height: 1.55; }

.praesia-card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  margin-top: auto;
  padding-top: 8px;
}

.praesia-price { font-size: 1.4rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.praesia-price-lg { font-size: 2rem; }

/* The issuance rule is printed on the card, not hidden in terms — it is the reason the
   credential outranks a completion certificate, so a buyer reads it before paying. */
.praesia-rule {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.praesia-rule li {
  position: relative;
  padding-left: 20px;
  font-size: .9rem;
  color: var(--praesia-ink-2);
  line-height: 1.5;
}
.praesia-rule li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .5em;
  width: 8px;
  height: 8px;
  border: 2px solid var(--praesia-accent);
  border-radius: 50%;
}

/* ── panels, buy bar, misc ───────────────────────────────────────────────────────────── */
.praesia-panel {
  background: var(--praesia-ground-2);
  border-radius: 4px;
  padding: 22px 24px;
  max-width: 760px;
}
.praesia-panel p { margin: 0; color: var(--praesia-ink-2); line-height: 1.6; max-width: var(--praesia-measure); }
.praesia-panel-rule { border-left: 3px solid var(--praesia-accent); }

.praesia-buybar {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
  padding: 22px 0 0;
  border-top: 1px solid var(--praesia-rule);
}
.praesia-buyform { margin: 0; }

.praesia-empty {
  background: var(--praesia-ground-2);
  border-radius: 4px;
  padding: 30px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: flex-start;
}
.praesia-empty-line { color: var(--praesia-ink-3); }

.praesia-detail,
.praesia-passport,
.praesia-catalogue,
.praesia-success { display: flex; flex-direction: column; gap: 4px; }

.praesia-next { margin-top: 20px; }

/* ── footer ──────────────────────────────────────────────────────────────────────────── */
.praesia-footer {
  border-top: 1px solid var(--praesia-rule);
  padding: 26px clamp(16px, 5vw, 48px);
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.praesia-footer-tag { font-weight: 600; margin: 0; font-size: .92rem; }
.praesia-footer-legal { color: var(--praesia-ink-3); margin: 0; font-size: .82rem; }

@media (prefers-reduced-motion: reduce) {
  .praesia-shell *, .praesia-shell *::before, .praesia-shell *::after {
    animation: none !important;
    transition: none !important;
  }
}

/* ── language control ────────────────────────────────────────────────────────────────── */
/* Lives in the Praesia topbar because suppressing the platform chrome (praesia/index.php)
   took the platform's own picker with it. Codes, not names: three words in sixteen files
   would be sixteen files of churn for something ES/CA/EN already says. */
.praesia-langs {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding-left: 14px;
  margin-left: 4px;
  border-left: 1px solid rgba(249, 244, 234, .22);
}
.praesia-lang {
  color: var(--praesia-panel-ink);
  opacity: .6;
  text-decoration: none;
  font-size: .66rem;
  font-weight: 700;
  letter-spacing: .1em;
  padding: 4px 6px;
  border-radius: 2px;
}
.praesia-lang:hover { opacity: 1; color: var(--praesia-accent); }
.praesia-lang.is-on { opacity: 1; color: var(--praesia-accent); }
.praesia-lang:focus-visible { outline: 3px solid var(--praesia-accent); outline-offset: 2px; }
