/* ═══════════════════════════════════════════════════════════════════════════
   tutorial.css — the guided-tour surface for the Studio CRM and the Client
   Portal. Loaded by BOTH pages; nothing here is surface-specific except the
   two token blocks at the top.

   WHY IT IS ONE FILE. The two products do not share a stylesheet — the CRM
   loads styles/crm.css, the portal loads tokens.css + portal.css — and they do
   not share a palette either (the CRM is gold-on-oxblood chrome, the portal is
   ivory-and-bloodstone stationery). A tour that shipped its own look would
   read as a third product bolted on. So this file declares ONE set of
   `--evo-t-*` tokens and then re-points them per surface, which is why every
   rule below can be written once.

   ⚠ EVERY COLOUR IS A var() WITH A LITERAL FALLBACK. The portal defines
   --bloodstone in tokens.css and the CRM does not define it at all; the CRM
   defines --accent and the portal does not. A bare var(--accent) resolves to
   *nothing* on the portal — not to a default — and an unset background-color
   on a dimming overlay is transparent, i.e. no dim at all. The fallbacks are
   what make one file safe on two palettes.

   ⚠ THE DIM IS FOUR RECTANGLES, NOT A BOX-SHADOW HOLE. The obvious trick is
   one element with `box-shadow: 0 0 0 9999px rgba(...)`, which is one node
   instead of four. It cannot be used here: box-shadow is painted, never
   hit-tested, so the "dimmed" area stays fully clickable and a tour step that
   says *click Guest List* could be satisfied by clicking anything at all.
   Four real rectangles around the spotlight dim AND block, and the hole is a
   genuine gap, so the highlighted control — and only it — receives the click.

   Z-INDEX BUDGET (both surfaces measured before choosing):
     portal .portal-hdr 200 · portal .inbox-drawer ~300 · CRM .drawer 100 ·
     CRM #crm-palette 500 · CRM #global-error-banner 99999
   The tour sits at 9000–9600: above every product chrome, deliberately BELOW
   the CRM's crash banner, because a JavaScript error must always be readable
   even when a tour is on top of the page.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  --evo-t-ink:        #1E0B0E;
  --evo-t-paper:      #FBF7EF;
  --evo-t-paper-2:    #FFFDF8;
  --evo-t-accent:     #B02A45;
  --evo-t-accent-ink: #FBF7EF;
  --evo-t-gold:       #BC9862;
  --evo-t-line:       rgba(30, 11, 14, .12);
  --evo-t-line-soft:  rgba(30, 11, 14, .07);
  --evo-t-muted:      rgba(30, 11, 14, .58);
  --evo-t-dim:        rgba(30, 11, 14, .62);
  /* ⚠ THE NINE TOKENS BELOW EXIST SO A SURFACE RE-POINT CAN REACH THE WHOLE FILE.
     Everything above was already a token; these nine values were written as literals
     in the rules and a rebind cannot reach a literal — so on the portal the tour kept
     painting the retired palette (old Onyx #1E0B0E, Ivory #FBF7EF, the structural teal
     #317254) however the tokens were re-pointed. Every default here is EXACTLY the
     value the rule used to carry, so the CRM renders unchanged; only
     body.evo-t-surface-portal moves. The one exception is stated at --evo-t-body. */
  --evo-t-ink-rgb:    30, 11, 14;      /* the ink as a triplet, for shadows and scrims */
  --evo-t-paper-rgb:  251, 247, 239;   /* the paper as a triplet, for washes on the dark plate */
  --evo-t-accent-rgb: 188, 152, 98;    /* the spotlight ring's halo — gold on both surfaces */
  --evo-t-on-dark:    #FBF7EF;         /* type ON the ink plate: the hotbar, the toast, a struck chip.
                                          Split out of --evo-t-paper, which is also the light TINT a
                                          hover falls to; one token cannot be both once the tint stops
                                          being near-white. */
  --evo-t-body:       rgba(30, 11, 14, .74);  /* secondary copy: step descriptions, modal paragraphs.
                                          ⚠ the modal paragraph was .72 and is now .74 — the only
                                          value in this block that moves the CRM, by +0.3:1, i.e.
                                          upward. Two near-identical alphas for one job is drift. */
  --evo-t-dim-modal:  rgba(30, 11, 14, .72);  /* the modal backdrop, deliberately deeper than --evo-t-dim */
  --evo-t-done:       #317254;         /* the completion tick and the done module mark */
  --evo-t-done-ink:   #FFFFFF;         /* type on that fill */
  --evo-t-gold-ink:   #1E0B0E;         /* type on the sandbox banner's fill */
  --evo-t-serif:      'Crimson Pro', Georgia, 'Times New Roman', serif;
  --evo-t-sans:       'Montserrat', 'Helvetica Neue', Arial, sans-serif;
  /* NO --evo-t-radius. Radius is brand LAW, not a per-surface value: only 0,
     2px and 50% exist (brand/brand.json → tokens.radius), and unlike the
     palette it does not change between the CRM and the portal, so there is
     nothing to re-point. Every rule below therefore writes the canonical
     token directly — `var(--m-r-input, 2px)`, same var-with-literal-fallback
     convention as the colours above. A private alias resolving to 2px was
     correct on screen but unverifiable by tooling: scripts/brand-lint.mjs
     reads CSS as text, cannot follow a custom property, and flagged all five
     use sites (2026-08-10). Spelling the brand token means the gate can prove
     the value instead of trusting it. */
  --evo-t-shadow:     0 18px 54px rgba(30, 11, 14, .22);
  --evo-t-z:          9000;
}

/* The CRM runs a darker, tighter chrome and a gold accent; the portal's
   bloodstone would read as an error state there. */
body.evo-t-surface-crm {
  --evo-t-paper:      #FBF7EF;
  --evo-t-paper-2:    #FFFFFF;
  --evo-t-accent:     #BC9862;
  --evo-t-accent-ink: #1E0B0E;
  /* ⚠ TEXT-ONLY. --evo-t-accent (#BC9862) is the CRM's gold — right on a border or a
     ring, 2.69:1 as small text on --evo-t-paper-2 (#FFFFFF), same shape as crm.css's
     --accent/--accent-ink split (crm.css:47-56): one ink cannot serve both a
     background and text on a light ground. This is that ink for the gold, darkened
     until it clears AA for normal text — 5.09:1 on #FFFFFF. Never use it as a
     background; --evo-t-accent still owns borders, rings and fills. */
  --evo-t-accent-text: #846A45;
  --evo-t-dim:        rgba(30, 11, 14, .68);
  --evo-t-serif:      'Libre Baskerville', Georgia, serif;
}

/* ═══ THE PORTAL SURFACE — chapter 08 of brand/EVORRAH_BRAND_SYSTEM_V15.html ═══
   The portal behind the door is painted in chapter 08 (Linen ground, Onyx ink, the
   five functional colours); the tour that runs on top of it was still on the retired
   palette, so the launcher alone put old Onyx #1E0B0E and an off-palette #FFFDF8 on
   every one of the 95 room views measured, and an open tour put Bloodstone #B02A45 on
   the primary button — the one control the book reserves for Deep Crimson, "the one
   thing you want them to press".

   ⚠ COLOUR IS TAKEN FROM CHAPTER 08 AND app/v15/style.css AND NOTHING ELSE (§24.1);
   brand.json's colour tokens are the previous palette. The quiet steps are written as
   rgba(20, 20, 20, α) rather than as the flattened hexes because the tour draws over
   whatever the room is showing: over Linen those alphas composite to §8.2's own
   flattened values exactly (.78 → #464542, .62 → #6B6864, .12 → #DDD6CE), and over a
   client's artwork they stay a wash instead of a wrong solid.

   The CRM is a different product with a different palette and is not touched: this
   block is scoped to the portal body, and tutorial.js is what stamps the class. */
body.evo-t-surface-portal {
  --evo-t-ink:        #141414;                /* §8.1 Onyx — 16.4:1 on Linen */
  --evo-t-ink-rgb:    20, 20, 20;
  --evo-t-body:       rgba(20, 20, 20, .78);  /* §8.2 secondary copy — #464542, 8.55:1 */
  --evo-t-muted:      rgba(20, 20, 20, .62);  /* §8.2 labels, meta — #6B6864, 4.94:1, the last AA
                                                 text step. It was .58, which lands below AA on
                                                 Linen; .62 is the book's own floor, not a guess. */
  --evo-t-paper:      #E7E3DD;                /* §8.1 Alabaster — the tint a card steps back to */
  --evo-t-paper-2:    #F8F1E7;                /* §8.1 Linen — the tour card's own paper */
  --evo-t-paper-rgb:  248, 241, 231;
  --evo-t-on-dark:    #F8F1E7;                /* Linen on the Onyx plate — 16.4:1 */
  --evo-t-accent:     #9D0617;                /* §8.3 Deep Crimson — NEXT STEP */
  --evo-t-accent-rgb: 157, 6, 23;
  --evo-t-accent-ink: #F8F1E7;                /* Linen on Deep Crimson — 7.58:1 */
  --evo-t-accent-text:#9D0617;
  --evo-t-done:       #3B6B24;                /* §8.3 Moss Fern — DONE */
  --evo-t-done-ink:   #F8F1E7;                /* Linen on Moss — 5.65:1 */
  --evo-t-gold:       #846439;                /* §8.3 Amber — the sandbox banner: attention, not alarm */
  --evo-t-gold-ink:   #F8F1E7;                /* Linen on Amber — 4.85:1. It was #1E0B0E, which is
                                                 2.2:1 on Amber; the book pairs every functional
                                                 fill with Linen type for exactly this reason. */
  --evo-t-line:       rgba(20, 20, 20, .12);  /* §8.2 panel edges — #DDD6CE */
  --evo-t-line-soft:  rgba(20, 20, 20, .07);
  --evo-t-dim:        rgba(20, 20, 20, .62);
  --evo-t-dim-modal:  rgba(20, 20, 20, .72);
  --evo-t-shadow:     0 18px 54px rgba(20, 20, 20, .22);
  /* §05: Inter is the infrastructure — "running paragraphs, list rows, table data,
     navigation, buttons, labels, captions". Montserrat is the WORDMARK ONLY and "is not
     available for headings, labels, buttons"; the tour had 156 nodes set in it. */
  --evo-t-sans:       'Inter', -apple-system, 'Helvetica Neue', Arial, sans-serif;
}

/* ── DIM + SPOTLIGHT ──────────────────────────────────────────────────────── */

.evo-t-scrim {
  position: fixed;
  background: var(--evo-t-dim);
  z-index: var(--evo-t-z);
  pointer-events: auto;
  transition: opacity .18s ease;
}
.evo-t-scrim.is-pass-through { pointer-events: none; }

/* The ring is decoration only — it must never intercept the click the step is
   asking the user to make. */
.evo-t-ring {
  position: fixed;
  z-index: calc(var(--evo-t-z) + 1);
  pointer-events: none;
  border: 2px solid var(--evo-t-accent);
  border-radius: 2px;
  box-shadow: 0 0 0 3px rgba(var(--evo-t-accent-rgb), .22), 0 8px 30px rgba(var(--evo-t-ink-rgb), .28);
  transition: top .22s cubic-bezier(.4, 0, .2, 1), left .22s cubic-bezier(.4, 0, .2, 1),
              width .22s cubic-bezier(.4, 0, .2, 1), height .22s cubic-bezier(.4, 0, .2, 1);
}
.evo-t-ring.is-waiting::after {
  content: '';
  position: absolute;
  inset: -6px;
  border: 1px solid var(--evo-t-accent);
  /* Was 7px, to sit concentric with the ring's old 4px at inset -6px. Both are
     2px now; at a 6px offset the corners no longer nest exactly, which is not
     visible at a 1px stroke and is the correct trade against inventing a radius. */
  border-radius: 2px;
  opacity: .5;
  animation: evo-t-pulse 1.8s ease-out infinite;
}
@keyframes evo-t-pulse {
  0%   { transform: scale(1);    opacity: .55; }
  70%  { transform: scale(1.06); opacity: 0; }
  100% { transform: scale(1.06); opacity: 0; }
}

/* ── THE STEP CARD ────────────────────────────────────────────────────────── */

.evo-t-card {
  position: fixed;
  z-index: calc(var(--evo-t-z) + 2);
  width: min(408px, calc(100vw - 32px));
  background: var(--evo-t-paper-2);
  border: 1px solid var(--evo-t-line);
  border-radius: var(--m-r-input, 2px);
  box-shadow: var(--evo-t-shadow);
  font-family: var(--evo-t-sans);
  color: var(--evo-t-ink);
  overflow: hidden;
}
.evo-t-card:focus { outline: none; }

.evo-t-card-bar { height: 2px; background: var(--evo-t-line-soft); }
.evo-t-card-bar > i {
  display: block; height: 100%;
  background: var(--evo-t-accent);
  transition: width .25s ease;
}

.evo-t-card-body { padding: 20px 22px 6px; }

.evo-t-eyebrow {
  display: flex; align-items: baseline; gap: 8px;
  font-size: .58rem; letter-spacing: .2em; text-transform: uppercase;
  color: var(--evo-t-muted); margin-bottom: 9px;
}
.evo-t-eyebrow b { font-weight: 600; color: var(--evo-t-accent-text, var(--evo-t-accent)); }
.evo-t-eyebrow .evo-t-count { margin-left: auto; letter-spacing: .12em; }

.evo-t-title {
  font-family: var(--evo-t-serif);
  font-weight: 400;
  font-size: 1.32rem;
  line-height: 1.22;
  margin: 0 0 9px;
}
.evo-t-desc {
  font-size: .82rem;
  line-height: 1.68;
  color: var(--evo-t-body);
  margin: 0;
}
.evo-t-desc + .evo-t-desc { margin-top: 9px; }
.evo-t-desc strong { font-weight: 600; color: var(--evo-t-ink); }

/* "Now do this" — the action line. Visually distinct from the explanation so
   a reader skimming knows which sentence is an instruction. */
.evo-t-do {
  display: flex; gap: 9px; align-items: flex-start;
  margin: 14px 0 2px; padding: 11px 13px;
  background: var(--evo-t-paper);
  border-left: 2px solid var(--evo-t-accent);
  font-size: .78rem; line-height: 1.55;
}
.evo-t-do::before { content: '➜'; color: var(--evo-t-accent); line-height: 1.5; }
.evo-t-do.is-done { border-left-color: var(--evo-t-done); opacity: .72; }
.evo-t-do.is-done::before { content: '✓'; color: var(--evo-t-done); }

/* The cross-system aside: "your studio sees this instantly." */
.evo-t-cross {
  margin: 14px 0 2px; padding: 11px 13px;
  border: 1px dashed var(--evo-t-line);
  background: transparent;
  font-size: .74rem; line-height: 1.6; color: var(--evo-t-muted);
}
.evo-t-cross b {
  display: block; font-size: .55rem; letter-spacing: .2em;
  /* §8.3 assigns Amber one meaning — RUNNING LATE — and §8.5 forbids a functional
     colour as text this small on a pale ground (this label is .55rem ≈ 10px). "Your
     studio sees this" is not a state, so it takes the quiet layer and the dashed border
     it already sits inside does the marking. */
  text-transform: uppercase; color: var(--evo-t-muted); margin-bottom: 5px;
}

.evo-t-card-foot {
  display: flex; align-items: center; gap: 8px;
  padding: 14px 22px 16px;
  border-top: 1px solid var(--evo-t-line-soft);
  margin-top: 14px;
  flex-wrap: wrap;
}
.evo-t-spacer { flex: 1 1 auto; }

.evo-t-btn {
  font-family: var(--evo-t-sans);
  font-size: .63rem; letter-spacing: .14em; text-transform: uppercase;
  padding: 9px 17px; min-height: 34px;
  border: 1px solid var(--evo-t-line); border-radius: var(--m-r-input, 2px);
  background: transparent; color: var(--evo-t-ink);
  cursor: pointer; transition: background .15s, border-color .15s, color .15s;
}
.evo-t-btn:hover { background: var(--evo-t-paper); }
.evo-t-btn.pri {
  background: var(--evo-t-accent); border-color: var(--evo-t-accent);
  color: var(--evo-t-accent-ink); font-weight: 600;
}
.evo-t-btn.pri:hover { filter: brightness(.93); }
.evo-t-btn.link {
  border-color: transparent; padding: 9px 6px;
  color: var(--evo-t-muted); letter-spacing: .1em;
}
.evo-t-btn.link:hover { color: var(--evo-t-ink); background: transparent; text-decoration: underline; }
.evo-t-btn[disabled] { opacity: .38; cursor: not-allowed; }
.evo-t-btn[disabled]:hover { background: transparent; }

/* The little arrow that ties the card to the thing it is talking about. */
.evo-t-card::before {
  content: '';
  position: absolute;
  width: 11px; height: 11px;
  background: var(--evo-t-paper-2);
  border: 1px solid var(--evo-t-line);
  transform: rotate(45deg);
  display: none;
}
.evo-t-card[data-arrow="top"]::before    { display: block; top: -6px;    left: var(--evo-t-arrow, 32px); border-right: none; border-bottom: none; }
.evo-t-card[data-arrow="bottom"]::before { display: block; bottom: -6px; left: var(--evo-t-arrow, 32px); border-left: none;  border-top: none; }
.evo-t-card[data-arrow="left"]::before   { display: block; left: -6px;   top: var(--evo-t-arrow, 24px);  border-right: none; border-top: none; }
.evo-t-card[data-arrow="right"]::before  { display: block; right: -6px;  top: var(--evo-t-arrow, 24px);  border-left: none;  border-bottom: none; }

/* ── MOBILE: the card becomes a sheet ─────────────────────────────────────── */
/* The landscape arm is not decorative. A phone turned sideways is 800–932px
   wide, so a width-only query stops applying at exactly the moment the user
   has the least vertical room — the same omission portal.css records having
   been caught once already. */
@media (max-width: 720px), (max-height: 500px) and (orientation: landscape) {
  .evo-t-card {
    position: fixed !important;
    left: 0 !important; right: 0 !important; bottom: 0 !important;
    top: auto !important;
    width: 100% !important;
    max-height: min(72vh, 560px);
    overflow-y: auto;
    border-radius: 2px 2px 0 0;
    border-left: none; border-right: none; border-bottom: none;
    box-shadow: 0 -14px 44px rgba(var(--evo-t-ink-rgb), .3);
  }
  .evo-t-card::before { display: none !important; }
  .evo-t-card-body { padding: 18px 18px 4px; }
  .evo-t-card-foot { padding: 12px 18px calc(14px + env(safe-area-inset-bottom, 0px)); }
  .evo-t-btn { min-height: 44px; padding: 12px 16px; }   /* thumb floor */
  .evo-t-title { font-size: 1.18rem; }
}

/* ── MODAL: welcome · academy · completion · help ─────────────────────────── */

.evo-t-modal {
  position: fixed; inset: 0;
  z-index: calc(var(--evo-t-z) + 400);
  background: var(--evo-t-dim-modal);
  display: flex; align-items: center; justify-content: center;
  padding: 24px;
  overflow-y: auto;
  font-family: var(--evo-t-sans);
}
.evo-t-modal-box {
  background: var(--evo-t-paper-2);
  border: 1px solid var(--evo-t-line);
  border-radius: var(--m-r-input, 2px);
  box-shadow: var(--evo-t-shadow);
  width: min(620px, 100%);
  max-height: calc(100vh - 48px);
  overflow-y: auto;
  color: var(--evo-t-ink);
}
.evo-t-modal-box.wide { width: min(880px, 100%); }
.evo-t-modal-head { padding: 34px 38px 0; }
.evo-t-modal-head .evo-t-eyebrow { margin-bottom: 12px; }
.evo-t-modal-h {
  font-family: var(--evo-t-serif); font-weight: 400;
  font-size: 2.05rem; line-height: 1.1; margin: 0 0 12px;
}
.evo-t-modal-p {
  font-size: .86rem; line-height: 1.72; color: var(--evo-t-body);
  margin: 0 0 6px; max-width: 58ch;
}
.evo-t-modal-body { padding: 18px 38px 4px; }
.evo-t-modal-foot {
  display: flex; gap: 10px; flex-wrap: wrap; align-items: center;
  padding: 20px 38px 30px;
}
@media (max-width: 720px) {
  .evo-t-modal { padding: 0; align-items: flex-end; }
  .evo-t-modal-box { max-height: 92vh; border-radius: 2px 2px 0 0; width: 100%; }
  .evo-t-modal-head { padding: 26px 20px 0; }
  .evo-t-modal-body { padding: 14px 20px 4px; }
  .evo-t-modal-foot { padding: 16px 20px calc(24px + env(safe-area-inset-bottom, 0px)); }
  .evo-t-modal-h { font-size: 1.6rem; }
  .evo-t-modal-foot .evo-t-btn { flex: 1 1 100%; min-height: 46px; }
}

/* ── ACADEMY (the module list) ────────────────────────────────────────────── */

.evo-t-track-head {
  display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
  margin: 4px 0 16px;
}
.evo-t-track-btn {
  font-size: .6rem; letter-spacing: .16em; text-transform: uppercase;
  padding: 8px 14px; min-height: 34px;
  border: 1px solid var(--evo-t-line); background: transparent;
  color: var(--evo-t-muted); cursor: pointer; border-radius: var(--m-r-input, 2px);
}
.evo-t-track-btn.on {
  background: var(--evo-t-ink); border-color: var(--evo-t-ink); color: var(--evo-t-on-dark);
}

.evo-t-meter { display: flex; align-items: center; gap: 12px; margin: 2px 0 20px; }
.evo-t-meter-bar {
  flex: 1; height: 5px; background: var(--evo-t-line-soft);
  /* 2px, not 50%: on a 5px-tall bar the seal radius draws an ellipse, not the
     pill the old 3px was approximating. */
  border-radius: 2px; overflow: hidden;
}
.evo-t-meter-bar > i { display: block; height: 100%; background: var(--evo-t-accent); transition: width .3s ease; }
.evo-t-meter-txt { font-size: .64rem; letter-spacing: .12em; text-transform: uppercase; color: var(--evo-t-muted); white-space: normal; line-height: 1.6; } /* EVR-021 (owner 2026-09-05): the line was clipped at the modal width on a laptop; it wraps now */

.evo-t-mods { list-style: none; margin: 0 0 4px; padding: 0; }
.evo-t-mod {
  display: flex; align-items: center; gap: 13px;
  width: 100%; text-align: left;
  padding: 13px 4px; min-height: 44px;
  border: none; border-bottom: 1px solid var(--evo-t-line-soft);
  background: transparent; cursor: pointer; color: inherit;
  font-family: var(--evo-t-sans);
}
.evo-t-mod:hover { background: var(--evo-t-paper); }
.evo-t-mod-mark {
  width: 21px; height: 21px; flex: 0 0 21px; border-radius: 50%;
  border: 1px solid var(--evo-t-line); display: flex; align-items: center; justify-content: center;
  font-size: .62rem; color: var(--evo-t-muted);
}
.evo-t-mod.is-done   .evo-t-mod-mark { background: var(--evo-t-done); border-color: var(--evo-t-done); color: var(--evo-t-done-ink); }
.evo-t-mod.is-here   .evo-t-mod-mark { border-color: var(--evo-t-accent); color: var(--evo-t-accent); }
.evo-t-mod.is-skipped .evo-t-mod-mark { border-style: dashed; }
/* ⚠ display:block ON BOTH, AND IT IS NOT COSMETIC (owner, 2026-08-25: "text is too close").
   These are <span>s inside a <button>, so they default to INLINE and the module name butts
   straight against its blurb — the help list rendered as "10 — SeatingTables, households,
   suggestions, and the people not yet placed." for every row, and "11 — Writing to your
   guestsMessages, who they reach…". A row whose own name is fused to its description is
   unreadable at a glance, which is the one thing an index has to be.
   THE TELL THAT IT WAS ALWAYS MEANT TO BE TWO LINES: .evo-t-mod-s already carried
   `margin-top: 2px`. Vertical margins DO NOT APPLY to inline elements, so that declaration
   had never once had an effect — the separation was written and silently discarded, which
   is why this looked deliberate enough to survive. Same defect, same fix, as the one
   already written up in app/scripts/portal-day-of-print.js (~line 93), where the same two
   spans rendered "DAY-OF SHEETOne page for whoever…".
   2px was also too tight to read as a break even once it applies; 4px is the gap used by
   the sibling list in that file. */
.evo-t-mod-txt { flex: 1; min-width: 0; }
.evo-t-mod-t { display: block; font-size: .82rem; font-weight: 500; line-height: 1.45; }
.evo-t-mod-s { display: block; font-size: .69rem; color: var(--evo-t-muted); margin-top: 4px; line-height: 1.5; }
.evo-t-mod-min { font-size: .6rem; letter-spacing: .1em; color: var(--evo-t-muted); white-space: nowrap; }

.evo-t-sec-h {
  font-size: .58rem; letter-spacing: .22em; text-transform: uppercase;
  color: var(--evo-t-muted); font-weight: 600; margin: 22px 0 8px;
}

/* Completion ticks */
.evo-t-wins { list-style: none; margin: 14px 0 0; padding: 0; }
.evo-t-wins li {
  display: flex; gap: 10px; align-items: flex-start;
  font-size: .82rem; line-height: 1.6; padding: 5px 0;
}
.evo-t-wins li::before { content: '✓'; color: var(--evo-t-done); font-weight: 700; }

/* ── HELP LAUNCHER ────────────────────────────────────────────────────────── */

.evo-t-launcher {
  position: fixed; right: 18px; bottom: 18px;
  z-index: calc(var(--evo-t-z) + 300);
  width: 44px; height: 44px; border-radius: 50%;
  border: 1px solid var(--evo-t-line);
  background: var(--evo-t-paper-2); color: var(--evo-t-ink);
  font-family: var(--evo-t-serif); font-size: 1.15rem; line-height: 1;
  box-shadow: 0 6px 22px rgba(var(--evo-t-ink-rgb), .18);
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.evo-t-launcher:hover { background: var(--evo-t-paper); }
.evo-t-launcher[hidden] { display: none; }
/* While a tour is running the launcher would sit on top of the scrim and read
   as a live control; the tour's own Exit is the way out. */
body.evo-t-running .evo-t-launcher { display: none; }
@media (max-width: 720px) {
  .evo-t-launcher { right: 12px; bottom: 12px; width: 46px; height: 46px; }
}

/* An inline "?" that can be dropped beside any heading. */
.evo-t-hint {
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; margin-left: 6px; vertical-align: middle;
  border: 1px solid currentColor; border-radius: 50%;
  font-size: 9px; font-weight: 700; font-style: normal; line-height: 1;
  opacity: .55; cursor: pointer; background: none; color: inherit;
  font-family: var(--evo-t-sans);
}
.evo-t-hint:hover { opacity: 1; }

/* ── EXPLAIN-THIS-SCREEN HOTSPOTS ─────────────────────────────────────────── */

.evo-t-hotspot {
  position: fixed;
  z-index: calc(var(--evo-t-z) + 260);
  width: 24px; height: 24px; border-radius: 50%;
  background: var(--evo-t-accent); color: var(--evo-t-accent-ink);
  border: 2px solid var(--evo-t-paper-2);
  font-family: var(--evo-t-sans); font-size: .66rem; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; box-shadow: 0 3px 12px rgba(var(--evo-t-ink-rgb), .3);
}
.evo-t-hotspot:hover { transform: scale(1.12); }
.evo-t-hotbar {
  position: fixed; left: 50%; transform: translateX(-50%); bottom: 18px;
  z-index: calc(var(--evo-t-z) + 300);
  display: flex; gap: 10px; align-items: center;
  background: var(--evo-t-ink); color: var(--evo-t-on-dark);
  /* Was a 30px pill. This is the one change here with real visual weight: the
     hotbar now reads as a struck plate rather than a chip, which is the point
     of the rule — "softness reads as software, not stationery". */
  padding: 10px 16px; border-radius: 2px;
  font-family: var(--evo-t-sans); font-size: .68rem; letter-spacing: .06em;
  box-shadow: var(--evo-t-shadow); max-width: calc(100vw - 24px);
}
.evo-t-hotbar .evo-t-btn { border-color: rgba(var(--evo-t-paper-rgb), .3); color: var(--evo-t-on-dark); min-height: 30px; padding: 6px 12px; }
.evo-t-hotbar .evo-t-btn:hover { background: rgba(var(--evo-t-paper-rgb), .12); }

/* ── SANDBOX BANNER ───────────────────────────────────────────────────────── */

.evo-t-sandbox {
  position: fixed; top: 0; left: 0; right: 0;
  z-index: calc(var(--evo-t-z) + 320);
  background: var(--evo-t-gold); color: var(--evo-t-gold-ink);
  font-family: var(--evo-t-sans); font-size: .64rem;
  letter-spacing: .14em; text-transform: uppercase; font-weight: 600;
  text-align: center; padding: 6px 12px 5px;
  box-shadow: 0 2px 10px rgba(var(--evo-t-ink-rgb), .18);
}
.evo-t-sandbox b { font-weight: 700; }
/* ⚠ NO opacity HERE. This is a sentence a client reads ("Nothing you press sends a
   message"), and on the portal the banner's fill is Amber with Linen type — 4.85:1,
   which is the book's own number and has no headroom. opacity:.8 took it to 3.75:1,
   measured. The house rule is to dim the numeral, never the label: the weight (400
   against the banner's 600), the case and the tracking already separate this line
   from "Tutorial mode", so the dimmer bought nothing and cost AA. */
.evo-t-sandbox span { text-transform: none; letter-spacing: .02em; font-weight: 400; }
@media (max-width: 720px) { .evo-t-sandbox { font-size: .58rem; letter-spacing: .08em; } }

/* ── TOAST (used when a step cannot be reached) ───────────────────────────── */
.evo-t-toast {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: 74px; z-index: calc(var(--evo-t-z) + 340);
  background: var(--evo-t-ink); color: var(--evo-t-on-dark);
  font-family: var(--evo-t-sans); font-size: .72rem; line-height: 1.5;
  padding: 11px 18px; border-radius: var(--m-r-input, 2px);
  max-width: min(440px, calc(100vw - 32px));
  box-shadow: var(--evo-t-shadow);
}
/* On a phone the card IS the bottom of the screen, so a toast anchored to the
   bottom lands on top of the step it is commenting on — measured: the
   "nothing happened" notice covered four lines of the card. Above the fold,
   under the tutorial-mode banner, is the only free space there.

   ⚠ ONLY WHILE A TOUR IS RUNNING, AND THAT SCOPE IS THE WHOLE POINT (WS02 check 02-04,
   2026-09-11). `body.evo-t-running` is added in Engine.start and removed in Engine.stop, so
   it is on the body exactly when a step CARD is on screen — the situation the paragraph above
   measured. Unscoped, the same rule pinned every OTHER toast to the top of the screen too,
   including the parting line an operator gets for choosing "Explore on my own" on their first
   run — and `top:52px` on a phone is the Command Center's search row. Measured by
   scripts/launch-readiness/ws02-04-app-device-matrix.mjs on 8 phone profiles (iPhone SE,
   iPhone 16 Pro Max, Galaxy S9+, Pixel 7, upright and sideways): `input#search-input` sat under
   `div.evo-t-toast` on all 8, and `⚙ Settings` and `? Help` too on the two smallest — for the
   5,200ms the toast lives. With no card on screen the default bottom anchor is free: 74px
   clears the 46px launcher parked at bottom:12px by 16px, which is why that number is 74.
   Guarded by test/cc-tutorial-toast-off-the-controls.test.mjs, which drives the product's own
   "Explore on my own" and fails if this rule loses its scope. */
@media (max-width: 720px), (max-height: 500px) and (orientation: landscape) {
  body.evo-t-running .evo-t-toast { top: 52px; bottom: auto; }
}

/* ── REDUCED MOTION ───────────────────────────────────────────────────────── */
/* Not a nicety: the ring animates its position on every step, and a tour is
   precisely the kind of long, moving sequence that triggers vestibular
   symptoms. Everything still WORKS — only the movement stops. */
@media (prefers-reduced-motion: reduce) {
  .evo-t-ring, .evo-t-scrim, .evo-t-card-bar > i, .evo-t-meter-bar > i { transition: none !important; }
  .evo-t-ring.is-waiting::after { animation: none; opacity: .45; }
  .evo-t-hotspot:hover { transform: none; }
}

/* ── FORCED COLOURS / HIGH CONTRAST ───────────────────────────────────────── */
@media (forced-colors: active) {
  .evo-t-card, .evo-t-modal-box { border: 1px solid CanvasText; }
  .evo-t-ring { border-color: Highlight; }
  .evo-t-scrim { background: transparent; }
}

/* Owner 2026-09-06: lists inside a step wear the card's own type (they used to fall out of the paragraph). */
.evo-t-desc-list { font-family: var(--evo-t-sans); }
.evo-t-desc-list ul { margin: 6px 0 0; padding-left: 18px; }
.evo-t-desc-list li { font-family: var(--evo-t-sans); font-size: .82rem; line-height: 1.6; color: var(--evo-t-body); margin: 0 0 4px; }
