/* HisaabFlow website - the component layer.
 *
 * LOAD ORDER: packages/core/design-tokens.css (the product theme and the three self-hosted
 * faces), then styles/tokens.css (generated from tokens.js), then this file.
 *
 * NOTHING HERE IS A VALUE. Every colour, length, duration and font size is a custom property,
 * either the product's (--canvas, --r-lg, --t-fast) or the website's (--w-*). The audit
 * (npm run design:audit) fails this file on a raw px, hex or ms.
 *
 * A COMPONENT NEVER NAMES A COLOUR. It names a role - --w-bg, --w-fg, --w-action - and the scene
 * it sits in decides what that is, by declaring a ground: <section data-ground="deep">.
 *
 * Classes are prefixed hf- so they cannot collide with the product's eg- classes, which this
 * page also loads.
 */

/* ------------------------------------------------------------------- base */
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
html.hf, .hf body { background: var(--w-bg); color: var(--w-fg); }
.hf body {
  font-family: var(--font);
  font-size: var(--w-fs-body);
  font-weight: var(--w-fw-body);
  line-height: var(--w-lh-body);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: clip;
}
/* THE RESETS WEIGH NOTHING. Both halves are inside :where(), so any class at all outranks
   them - the website's own and, just as importantly, the product's: an eg-pill used on this
   page keeps the colour the product gave it instead of inheriting the page's ink. */
:where(.hf) :where(h1, h2, h3, h4, p, ul, ol, figure, blockquote) { margin: var(--sp-0); padding: var(--sp-0); }
:where(.hf) :where(ul, ol) { list-style: none; }
:where(.hf) :where(a) { color: inherit; text-decoration: none; }
:where(.hf) :where(button, input) { font: inherit; color: inherit; }
:where(.hf) :where(img, video, canvas, svg) { display: block; max-width: 100%; }

/* A ground repaints its own box and re-answers every role for what is inside it. */
[data-ground] { background: var(--w-bg); color: var(--w-fg); }

/* Selection carries the brand: the accent as a surface, ink on it, the measured pair. */
.hf ::selection { background: var(--lime-500); color: var(--ink); }

/* Keyboard focus. One ring, in the ground's own text colour, never removed. */
.hf :focus-visible {
  outline: var(--w-focus-w) solid var(--w-fg);
  outline-offset: var(--w-focus-offset);
  border-radius: var(--r-xs);
}

/* ------------------------------------------------------------------- type */
.hf-mega, .hf-display, .hf-h2, .hf-h3 { text-wrap: balance; }
.hf-mega    { font-size: var(--w-fs-mega);    line-height: var(--w-lh-mega);    letter-spacing: var(--w-ls-mega);    font-weight: var(--w-fw-mega); }
.hf-display { font-size: var(--w-fs-display); line-height: var(--w-lh-display); letter-spacing: var(--w-ls-display); font-weight: var(--w-fw-display); }
.hf-h2      { font-size: var(--w-fs-h2);      line-height: var(--w-lh-h2);      letter-spacing: var(--w-ls-h2);      font-weight: var(--w-fw-h2); }
.hf-h3      { font-size: var(--w-fs-h3);      line-height: var(--w-lh-h3);      letter-spacing: var(--w-ls-h3);      font-weight: var(--w-fw-h3); }
.hf-lead    { font-size: var(--w-fs-lead);    line-height: var(--w-lh-lead);    letter-spacing: var(--w-ls-lead);    font-weight: var(--w-fw-lead); max-width: var(--w-measure-lead); text-wrap: pretty; }
.hf-body    { font-size: var(--w-fs-body);    line-height: var(--w-lh-body);    letter-spacing: var(--w-ls-body);    font-weight: var(--w-fw-body); max-width: var(--w-measure); text-wrap: pretty; }
.hf-label   { font-size: var(--w-fs-label);   line-height: var(--w-lh-label);   letter-spacing: var(--w-ls-label);   font-weight: var(--w-fw-label); }
.hf-cap     { font-size: var(--w-fs-cap);     line-height: var(--w-lh-cap);     letter-spacing: var(--w-ls-cap);     font-weight: var(--w-fw-cap); }
.hf-quiet   { color: var(--w-quiet); }

/* THE MONEY FACE. Dot-matrix, and only for a money figure: the font file holds the glyphs a
   figure is made of and nothing else, so a word set in it falls back to the text face. */
.hf-fig {
  font-family: var(--font-money), var(--font);
  font-size: var(--w-fs-figure);
  line-height: var(--w-lh-figure);
  letter-spacing: var(--w-ls-figure);
  font-weight: var(--fw-regular);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.hf-fig--xl { font-size: var(--w-fs-figure-xl); line-height: var(--w-lh-figure-xl); letter-spacing: var(--w-ls-figure-xl); }

/* An icon beside a label. Phosphor, by ligature, from the product's own font file. */
.hf-icon {
  font-family: var(--font-icon);
  font-size: var(--w-icon);
  font-weight: normal; font-style: normal; line-height: 1;
  letter-spacing: normal; text-transform: none; white-space: nowrap;
  font-feature-settings: 'liga'; font-variant-ligatures: discretionary-ligatures;
  display: inline-block; flex: none;
}

/* ----------------------------------------------------------------- layout */
.hf-wrap { width: min(100% - 2 * var(--w-gutter), var(--w-maxw)); margin-inline: auto; }
.hf-scene { padding-block: var(--w-g-scene); position: relative; }
.hf-scene--tight { padding-block: var(--w-g-block); }
.hf-group { display: flex; flex-direction: column; gap: var(--w-g-group); }
/* A column stretches its children by default, which turns a tag or a button into a bar the
   width of the page. Anything that is sized by its own content keeps that size. */
:where(.hf-group, .hf-price, .hf-price__head) > :where(.hf-tag, .hf-btn, .hf-sticker, .hf-said, .hf-fig, .hf-guru) { align-self: flex-start; }
.hf-blocks { display: flex; flex-direction: column; gap: var(--w-g-block); }
.hf-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--w-g-sibling); }
.hf-grid { display: grid; grid-template-columns: repeat(var(--w-cols-phone), minmax(0, 1fr)); column-gap: var(--w-col-gap); row-gap: var(--w-g-group); }
@media (min-width: 900px) { .hf-grid { grid-template-columns: repeat(var(--w-cols), minmax(0, 1fr)); } }

/* A full-width panel that IS a scene: rounded, inset from the edges by the gutter. */
.hf-panel {
  border-radius: var(--w-scene-r);
  padding: var(--w-g-block) var(--w-gutter);
  overflow: clip;
  position: relative;
}

/* The page's one texture. A dot of one size at one pitch, in the ground's own dot colour. */
.hf-dots {
  background-image: radial-gradient(circle, var(--w-grid-dot) var(--w-dot-size), transparent var(--w-dot-size));
  background-size: var(--w-dot-pitch) var(--w-dot-pitch);
}

/* ------------------------------------------------------------ highlighter */
/* One marked word per headline: the accent as a block behind the word, the word in the
   colour that was measured on it. */
.hf-mark {
  position: relative;
  display: inline-block;
  color: var(--w-on-accent);
  isolation: isolate;
  white-space: nowrap;
}
.hf-mark::before {
  content: '';
  position: absolute;
  inset: var(--w-mark-bleed-top) calc(-1 * var(--w-mark-bleed-x)) var(--w-mark-bleed-bottom);
  background: var(--w-accent);
  border-radius: var(--w-mark-r);
  transform: rotate(var(--w-mark-tilt)) scaleX(var(--hf-mark-in, 1));
  transform-origin: left center;
  transition: transform var(--w-t-slow) var(--w-ease-in-out);
  z-index: var(--w-z-below);
}
/* Waiting to be drawn. The swipe is the entrance, so the word reads before the block arrives.
   Only under .hf-motion: see the note on reveals below. */
.hf-motion .hf-mark[data-drawn="false"] { --hf-mark-in: 0; color: inherit; }
/* A FIGURE THAT IS NOT BEING TOLD YET: the same stroke of the highlighter, drawn where the
   number would be, with nothing under it. What it stands for is said in words inside it, for
   a screen reader. It is a blank on purpose, and never a number that was made up. */
.hf-redact { display: inline-block; position: relative; width: var(--w-redact-w); height: var(--w-redact-h); vertical-align: baseline; }
.hf-redact::before { content: ''; position: absolute; inset: var(--sp-0); background: var(--w-accent); border-radius: var(--w-mark-r); transform: rotate(var(--w-mark-tilt)); }
.hf-mark { transition: color var(--w-t-med) var(--w-ease); }

/* ----------------------------------------------------------------- button */
.hf-btn {
  display: inline-flex; align-items: center; justify-content: space-between;
  gap: var(--w-g-control);
  min-height: var(--w-btn-h);
  padding-inline: var(--w-btn-pad-start) var(--w-btn-pad-end);
  border: var(--sp-0); border-radius: var(--r-pill);
  background: var(--w-action); color: var(--w-on-action);
  font-size: var(--w-fs-label); font-weight: var(--w-fw-label); letter-spacing: var(--w-ls-label); line-height: var(--w-lh-label);
  white-space: nowrap; cursor: pointer; user-select: none;
  transition: transform var(--w-t-fast) var(--w-ease);
}
.hf-btn__seat {
  display: grid; place-items: center; flex: none;
  width: var(--w-btn-seat); height: var(--w-btn-seat);
  border-radius: var(--r-pill);
  background: var(--w-seat); color: var(--w-on-seat);
  transition: transform var(--w-t-fast) var(--w-ease);
}
.hf-btn__seat .hf-icon { transition: transform var(--w-t-fast) var(--w-ease); }
.hf-btn:active { transform: var(--w-hover-press); }

/* Pointer hover only: a tap on a touch screen fires a false hover and leaves it stuck. */
@media (hover: hover) and (pointer: fine) {
  .hf-btn:hover .hf-btn__seat { transform: var(--w-hover-grow); }
  /* The arrow turns from "onward" to "up and onward". It is the one flourish a button has. */
  .hf-btn:hover .hf-btn__seat .hf-icon { transform: rotate(-45deg); }
}

.hf-btn--sm { min-height: var(--w-btn-h-sm); padding-inline-start: var(--w-btn-pad-start-sm); }
.hf-btn--sm .hf-btn__seat { width: var(--w-btn-seat-sm); height: var(--w-btn-seat-sm); }

/* The second action. No fill: a ring in the text colour, which is ink or white and so clears
   3:1 on every ground without help. */
.hf-btn--quiet {
  background: transparent; color: var(--w-fg);
  box-shadow: inset 0 0 0 var(--w-stroke) var(--w-fg);
  padding-inline: var(--w-btn-pad-start);
  justify-content: center;
}

/* A LINK IN A LINE OF TEXT, outside a written page: underlined, because in a sentence nothing
   else says it is one. */
.hf-link { text-decoration: underline; text-decoration-thickness: from-font; text-underline-position: from-font; }
@media (hover: hover) and (pointer: fine) { .hf-link:hover { background: var(--w-accent); color: var(--w-on-accent); text-decoration-color: transparent; } }

/* The action that cannot be taken back: taking a note down, deleting a draft. It wears the
   colour that means so wherever it is, and it is only ever the second press of two. */
.hf-btn--danger { background: var(--danger); color: var(--ink-inv); padding-inline: var(--w-btn-pad-start); justify-content: center; }

.hf-btn:disabled, .hf-btn[aria-disabled="true"] {
  background: var(--w-well); color: var(--w-quiet); cursor: not-allowed; box-shadow: none;
}
.hf-btn:disabled .hf-btn__seat, .hf-btn[aria-disabled="true"] .hf-btn__seat { background: transparent; color: var(--w-quiet); transform: none; }

/* Loading: the arrow leaves and a ring turns in its seat. The label stays, so the button
   never changes width under the pointer. */
.hf-btn[aria-busy="true"] { cursor: progress; }
.hf-btn[aria-busy="true"] .hf-icon { visibility: hidden; }
.hf-btn[aria-busy="true"] .hf-btn__seat::after {
  content: ''; position: absolute;
  width: var(--sp-16); height: var(--sp-16);
  border-radius: var(--r-pill);
  border: var(--w-stroke) solid currentColor; border-top-color: transparent;
  animation: hf-turn var(--w-t-slow) linear infinite;
}
.hf-btn__seat { position: relative; }
@keyframes hf-turn { to { transform: rotate(1turn); } }

/* -------------------------------------------------------------------- tag */
.hf-tag {
  display: inline-flex; align-items: center; gap: var(--w-g-inline);
  min-height: var(--w-tag-h); padding: var(--w-tag-pad);
  border-radius: var(--r-pill);
  border: var(--sp-0);
  background: var(--w-well); color: var(--w-fg);
  font-size: var(--w-fs-cap); font-weight: var(--w-fw-label); line-height: var(--w-lh-label);
  white-space: nowrap;
}
/* A tag that is a button: a filter, a mood. It answers a press the way every control does. */
button.hf-tag { cursor: pointer; transition: transform var(--w-t-fast) var(--w-ease); }
button.hf-tag:active { transform: var(--w-hover-press); }
button.hf-tag[aria-pressed="true"] { background: var(--w-accent); color: var(--w-on-accent); }
.hf-tag__dot { width: var(--w-tag-dot); height: var(--w-tag-dot); border-radius: var(--r-pill); background: currentColor; flex: none; }
.hf-tag--accent { background: var(--w-accent); color: var(--w-on-accent); }

/* -------------------------------------------------------------------- nav */
/* A pill, detached from the top edge. The blur is on this one fixed element and nowhere else. */
.hf-nav {
  display: flex; align-items: center; justify-content: space-between; gap: var(--w-g-sibling);
  width: min(100% - 2 * var(--w-gutter), var(--w-nav-maxw));
  min-height: var(--w-nav-h);
  padding: var(--w-nav-pad); padding-inline-start: var(--w-btn-pad-start);
  border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--surface) 86%, transparent);
  color: var(--ink);
  -webkit-backdrop-filter: blur(var(--w-nav-blur)); backdrop-filter: blur(var(--w-nav-blur));
  box-shadow: inset 0 0 0 var(--c-hairline-w, var(--sp-0)) var(--hairline);
}
.hf-nav--fixed { position: fixed; top: var(--w-nav-offset); left: 50%; transform: translateX(-50%); z-index: var(--w-z-nav); }
.hf-nav__brand { display: inline-flex; align-items: center; gap: var(--g-tight); font-size: var(--w-fs-lead); font-weight: var(--fw-bold); letter-spacing: var(--w-ls-h3); white-space: nowrap; }
/* The app icon, beside the name. It carries its own rounded shape, so it is given no corner here. */
.hf-nav__mark { width: var(--w-nav-mark); height: var(--w-nav-mark); flex: none; }
.hf-nav__links { display: none; align-items: center; gap: var(--w-g-inline); }
@media (min-width: 900px) { .hf-nav__links { display: flex; } }
.hf-nav__link {
  display: inline-flex; align-items: center; min-height: var(--w-touch);
  padding-inline: var(--w-g-control); border-radius: var(--r-pill);
  font-size: var(--w-fs-label); font-weight: var(--fw-medium);
  transition: background var(--w-t-fast) var(--w-ease);
}
@media (hover: hover) and (pointer: fine) { .hf-nav__link:hover { background: var(--field); } }
.hf-nav__link[aria-current="true"] { background: var(--dark); color: var(--ink-inv); }
/* The page the reader is on: its name is held down, as a menu's is while its page is open. */
.hf-nav__link[aria-current="page"] { background: var(--field); }
/* The navigation is always on its own light surface, whatever scene is behind it, so its
   action is answered for that surface rather than inherited from the scene. */
.hf-nav .hf-btn { --w-action: var(--deep); --w-on-action: var(--ink-inv); --w-seat: var(--lime-500); --w-on-seat: var(--ink); }

.hf-nav__link[aria-disabled="true"] { color: var(--mute); cursor: default; }
.hf-nav__end { display: flex; align-items: center; gap: var(--g-tight); }
/* The phone menu's button, and the button that closes it. A round seat a thumb can hit. */
.hf-nav__open {
  display: inline-grid; place-items: center; flex: none;
  width: var(--w-touch); height: var(--w-touch); border-radius: var(--r-pill);
  border: var(--sp-0); background: var(--field); color: inherit; font-size: var(--i-lg); cursor: pointer;
}
@media (min-width: 900px) { .hf-nav .hf-nav__open { display: none; } }

/* ------------------------------------------------------------------- menu */
/* A menu under a name in the navigation. It is a native <details>: the name is its <summary>,
   so it opens with the keyboard and with no script. The panel is the one other place the
   popover shadow is used, because it is a layer above the page. */
.hf-menu { position: relative; }
.hf-menu > summary { list-style: none; gap: var(--g-inline); cursor: pointer; user-select: none; -webkit-user-select: none; }
.hf-menu > summary::-webkit-details-marker { display: none; }
.hf-menu__caret { font-size: var(--i-sm); transition: transform var(--w-t-fast) var(--w-ease); }
.hf-menu[open] .hf-menu__caret { transform: rotate(180deg); }
/* The name is held down while its menu is open, and while the reader is on one of its pages. */
.hf-menu[open] > summary, .hf-menu:has([aria-current="page"]) > summary { background: var(--field); }
.hf-menu__panel {
  position: absolute; inset-block-start: calc(100% + var(--w-nav-pad) + var(--g-tight)); inset-inline-start: var(--sp-0);
  width: var(--w-menu-w); max-width: calc(100vw - 2 * var(--w-gutter));
  display: grid; padding: var(--w-nav-pad);
  border-radius: var(--r-lg); background: var(--surface); color: var(--ink);
  box-shadow: var(--w-sticker-shadow), inset 0 0 0 var(--c-hairline-w, var(--sp-0)) var(--hairline);
}
.hf-menu__item {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; column-gap: var(--g-control);
  min-height: var(--w-touch); padding: var(--sp-10) var(--sp-12); border-radius: var(--r-md);
  transition: background var(--w-t-fast) var(--w-ease);
}
.hf-menu__seat {
  display: grid; place-items: center; width: var(--w-btn-seat); height: var(--w-btn-seat);
  border-radius: var(--r-pill); background: var(--field); font-size: var(--i-lg);
  transition: background var(--w-t-fast) var(--w-ease);
}
.hf-menu__text { display: flex; flex-direction: column; }
.hf-menu__text b { font-size: var(--w-fs-label); font-weight: var(--fw-bold); }
.hf-menu__text span { font-size: var(--w-fs-cap); color: var(--mute); }
.hf-menu__item[aria-current="page"] { background: var(--hover); }
.hf-menu__item[aria-current="page"] .hf-menu__seat { background: var(--lime-500); }
.hf-menu__item[aria-disabled="true"] b { color: var(--mute); }
@media (hover: hover) and (pointer: fine) {
  a.hf-menu__item:hover { background: var(--hover); }
  a.hf-menu__item:hover .hf-menu__seat { background: var(--lime-500); }
}
@media (prefers-reduced-motion: no-preference) {
  .hf-menu[open] > .hf-menu__panel { animation: hf-menu-in var(--w-t-fast) var(--w-ease-out); }
  @keyframes hf-menu-in { from { opacity: 0; transform: translateY(calc(var(--sp-8) * -1)); } }
}

/* ------------------------------------------------------------------ sheet */
/* The phone's menu: the whole screen, on the deep ground, with the same three things at a size
   a thumb can hit. It is a modal dialog, so the page behind it cannot be reached or scrolled.
   The links scroll if a small screen cannot hold them; the action stays in view below them. */
.hf-sheet {
  width: 100%; height: 100%; max-width: none; max-height: none; margin: var(--sp-0); border: var(--sp-0);
  padding: var(--w-nav-offset) var(--w-gutter) var(--w-g-group);
  background: var(--w-bg); color: var(--w-fg); overscroll-behavior: contain;
}
.hf-sheet[open] { display: flex; flex-direction: column; gap: var(--w-g-group); }
.hf-sheet__top { display: flex; align-items: center; justify-content: space-between; flex: none; min-height: var(--w-nav-h); }
.hf-sheet__top .hf-nav__open { background: var(--w-well); }
.hf-sheet__body { flex: 1 1 auto; min-height: var(--sp-0); overflow-y: auto; display: grid; align-content: start; gap: var(--w-g-group); }
.hf-sheet__group { display: grid; gap: var(--g-tight); }
.hf-sheet__link { display: flex; flex-direction: column; justify-content: center; min-height: var(--w-touch); }
.hf-sheet__link[aria-disabled="true"] { flex-direction: row; justify-content: flex-start; align-items: center; gap: var(--g-control); color: var(--w-quiet); }
.hf-sheet > .hf-btn { flex: none; justify-content: space-between; }

/* ------------------------------------------------------------------ trail */
/* WHAT YOU HAVE READ, AND WHAT IS LEFT. The parts of a long page, as a list of links that
   travels with the reader. js/trail.js marks each part read, here or ahead, puts the Guru on
   the one being read, and counts. It is drawn in two shapes, chosen by the room there is:

     hf-trail--rail   a capsule in the page's margin: a dot per part, the Guru as "you are here"
     hf-trail--pill   a pill at the foot of the screen: the Guru, the part's name, the count.
                      Pressing it opens the list of parts above it.

   Like the navigation it is always on its own light surface, whatever scene is behind it.
   Until the script has chosen a shape it is not shown: a page reads from top to bottom
   without it, and a list of links with no place to stand would sit on top of the page. */
.hf-trail { --hf-y: var(--sp-0); position: fixed; z-index: calc(var(--w-z-nav) - 1); color: var(--ink); }
.hf-trail:not(.hf-trail--rail):not(.hf-trail--pill) { display: none; }
/* In a specimen, or anywhere it belongs to a box and not to the screen. */
.hf-trail--inset { position: absolute; }
.hf-trail__stops { position: relative; display: flex; flex-direction: column; }
.hf-trail__stop { display: flex; align-items: center; position: relative; min-height: var(--w-trail-step); }
.hf-trail__dot {
  flex: none; width: var(--w-trail-dot); height: var(--w-trail-dot); border-radius: var(--r-pill);
  box-shadow: inset 0 0 0 var(--w-focus-w) var(--faint);
  transition: background var(--w-t-fast) var(--w-ease), box-shadow var(--w-t-fast) var(--w-ease), opacity var(--w-t-fast) var(--w-ease);
}
[data-state="read"] > .hf-trail__stop .hf-trail__dot { background: var(--lime-500); box-shadow: inset 0 0 0 var(--w-focus-w) var(--deep); }
.hf-trail__guru { width: var(--w-trail-guru); height: var(--w-trail-guru); pointer-events: none; }
.hf-trail__toggle { display: flex; align-items: center; gap: var(--g-tight); border: var(--sp-0); padding: var(--sp-0); background: transparent; color: inherit; font: inherit; }
.hf-trail__count { font-size: var(--w-fs-cap); font-weight: var(--w-fw-label); line-height: var(--w-lh-label); color: var(--mute); white-space: nowrap; font-variant-numeric: tabular-nums; }
.hf-trail__count b { color: var(--ink); font-weight: var(--fw-bold); }

/* THE RAIL. It stands in the page's margin, centred on the screen's height. The bar that holds
   the Guru and the count dissolves, so the Guru can stand among the stops. */
.hf-trail--rail {
  inset-inline-end: calc((var(--w-gutter) - var(--w-trail-width)) / 2); inset-block-start: 50%; translate: 0 -50%;
  display: grid; justify-items: center; gap: var(--g-inline);
  width: var(--w-trail-width); padding-block: var(--w-trail-pad); border-radius: var(--r-pill);
  background: var(--surface); box-shadow: inset 0 0 0 var(--c-hairline-w, var(--sp-0)) var(--hairline);
}
.hf-trail--rail .hf-trail__bar { display: contents; }
.hf-trail--rail .hf-trail__stops { inline-size: 100%; }
.hf-trail--rail .hf-trail__stop { inline-size: 100%; justify-content: center; }
/* The Guru stands where the dot of the part being read would be. */
.hf-trail--rail [data-state="here"] > .hf-trail__stop .hf-trail__dot { opacity: 0; }
.hf-trail--rail .hf-trail__guru {
  position: absolute; inset-block-start: var(--sp-0); inset-inline-start: calc((100% - var(--w-trail-guru)) / 2);
  transform: translateY(var(--hf-y)); transition: transform var(--w-t-med) var(--w-ease-out);
}
/* A part's name: said when you arrive at it, and whenever its stop is pointed at. */
.hf-trail--rail .hf-trail__name {
  position: absolute; inset-inline-end: calc(100% + var(--g-inline)); white-space: nowrap; pointer-events: none;
  padding: var(--sp-6) var(--sp-12); border-radius: var(--r-pill);
  background: var(--dark); color: var(--ink-inv);
  font-size: var(--w-fs-cap); font-weight: var(--w-fw-label); line-height: var(--w-lh-label);
  opacity: 0; transform: translateX(var(--sp-6)); transition: opacity var(--w-t-fast) var(--w-ease), transform var(--w-t-fast) var(--w-ease);
}
.hf-trail--rail .hf-trail__stop:focus-visible .hf-trail__name, .hf-trail--rail .is-new > .hf-trail__stop .hf-trail__name { opacity: 1; transform: none; }
@media (hover: hover) and (pointer: fine) { .hf-trail--rail .hf-trail__stop:hover .hf-trail__name { opacity: 1; transform: none; } }
.hf-trail--rail .hf-trail__now { display: none; }
.hf-trail--rail .hf-trail__toggle { pointer-events: none; }

/* THE PILL. At the foot of the screen, where there is no margin to stand in. The bar is the
   pill: the Guru, the name of the part being read, the count, and a line that fills as the
   page is read. Pressing it opens the parts above it, each with its name, to go to one. */
.hf-trail--pill {
  inset-inline: 0; margin-inline: auto; inset-block-end: max(var(--w-nav-offset), env(safe-area-inset-bottom));
  width: max-content; max-width: calc(100% - 2 * var(--w-gutter));
  transition: opacity var(--w-t-fast) var(--w-ease);
}
.hf-trail--pill .hf-trail__bar {
  position: relative; display: flex; align-items: center; gap: var(--g-inline);
  min-height: var(--w-touch); padding-inline: var(--sp-4) var(--sp-16); border-radius: var(--r-pill); overflow: clip;
  background: var(--surface); box-shadow: var(--w-sticker-shadow), inset 0 0 0 var(--c-hairline-w, var(--sp-0)) var(--hairline);
}
.hf-trail--pill .hf-trail__bar::after {
  content: ''; position: absolute; inset-inline: var(--sp-0); inset-block-end: var(--sp-0); height: var(--w-trail-fill);
  background: var(--lime-500); transform-origin: left center; transform: scaleX(var(--hf-read, 0));
  transition: transform var(--w-t-med) var(--w-ease-out);
}
.hf-trail--pill .hf-trail__toggle { min-height: var(--w-touch); min-width: var(--sp-0); cursor: pointer; }
.hf-trail--pill .hf-trail__now { min-width: var(--sp-0); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--w-fs-label); font-weight: var(--fw-bold); }
.hf-trail--pill .hf-trail__stops {
  display: none; position: absolute; inset-block-end: calc(100% + var(--g-tight)); inset-inline-start: 50%; translate: -50% 0;
  width: max-content; max-width: calc(100vw - 2 * var(--w-gutter)); padding: var(--w-trail-pad); border-radius: var(--r-lg);
  background: var(--surface); box-shadow: var(--w-sticker-shadow), inset 0 0 0 var(--c-hairline-w, var(--sp-0)) var(--hairline);
}
.hf-trail--pill[data-open="true"] .hf-trail__stops { display: flex; }
.hf-trail--pill .hf-trail__stop { gap: var(--g-control); min-height: var(--w-touch); padding-inline: var(--sp-12) var(--sp-20); border-radius: var(--r-md); font-size: var(--w-fs-label); font-weight: var(--fw-medium); }
.hf-trail--pill [data-state="here"] > .hf-trail__stop { background: var(--hover); font-weight: var(--fw-bold); }
.hf-trail--pill [data-state="here"] > .hf-trail__stop .hf-trail__dot { background: var(--dark); box-shadow: none; }
/* While something is being typed, the pill steps aside: it would sit on the field. */
body:has(input:focus, textarea:focus) .hf-trail--pill:not(.hf-trail--inset) { opacity: 0; pointer-events: none; }
/* And the foot of the page leaves room for it, so the last line is not under the pill. */
body:has(.hf-trail--pill:not(.hf-trail--inset)) > footer { padding-block-end: calc(var(--w-touch) + 2 * var(--w-nav-offset)); }
@media (prefers-reduced-motion: reduce) { .hf-trail__guru, .hf-trail--pill .hf-trail__bar::after { transition: none; } }

/* ---------------------------------------------------------------- sticker */
/* A thing ON the page: die-cut edge, the product's one shadow, left crooked on purpose. */
.hf-sticker {
  display: inline-flex; align-items: center; gap: var(--w-g-inline);
  padding: var(--w-sticker-pad);
  border: var(--w-sticker-diecut) solid var(--raised);
  border-radius: calc(var(--w-sticker-r) + var(--w-sticker-diecut));
  background: var(--lime-500); color: var(--ink);
  font-size: var(--w-fs-lead); font-weight: var(--fw-bold); line-height: var(--w-lh-label); letter-spacing: var(--w-ls-lead);
  white-space: nowrap; user-select: none; -webkit-user-select: none;
  box-shadow: var(--w-sticker-shadow);
  transform: translate(var(--hf-x, 0), var(--hf-y, 0)) rotate(var(--hf-rot, var(--w-sticker-rot-1))) scale(var(--hf-scale, 1));
  transition: box-shadow var(--w-t-fast) var(--w-ease);
  position: relative; z-index: var(--w-z-sticker);
}
.hf-sticker:nth-child(4n + 2) { --hf-rot: var(--w-sticker-rot-3); }
.hf-sticker:nth-child(4n + 3) { --hf-rot: var(--w-sticker-rot-2); }
.hf-sticker:nth-child(4n + 4) { --hf-rot: var(--w-sticker-rot-4); }
.hf-sticker--ink   { background: var(--dark); color: var(--lime-500); }
.hf-sticker--deep  { background: var(--deep); color: var(--ink-inv); }
.hf-sticker--paper { background: var(--surface); color: var(--ink); }
.hf-sticker--round { border-radius: var(--r-pill); }
/* A sticker that carries a figure is large enough for the money face to resolve. */
.hf-sticker .hf-fig { font-size: var(--font-money-min); }
[data-drag] { cursor: grab; touch-action: none; user-select: none; -webkit-user-select: none; }
/* ONCE IT HAS BEEN PICKED UP, ITS POSITION IS NEVER EASED. A thing that arrived with a slow
   rise keeps that transition on its transform, and a drag written through the same transform
   then trails the hand by the length of the rise. From the first grab on, only the shadow eases. */
[data-drag].is-loose { transition: box-shadow var(--w-t-fast) var(--w-ease); }
[data-drag].is-held { cursor: grabbing; --hf-scale: var(--w-sticker-lift); box-shadow: var(--w-sticker-shadow-lifted); z-index: calc(var(--w-z-sticker) + 1); }

/* ---------------------------------------------------------------- receipt */
/* Paper, torn top and bottom. The teeth are a mask, so the receipt has no border to drift. */
.hf-receipt {
  --hf-tooth: var(--w-receipt-tooth);
  --hf-depth: calc(var(--w-receipt-tooth) / 2);
  width: min(100%, var(--w-receipt-w));
  padding: var(--w-receipt-pad);
  padding-block: calc(var(--sp-28) + var(--hf-depth));
  background: var(--raised); color: var(--ink);
  font-family: var(--font-mono);
  font-size: var(--w-fs-cap); line-height: var(--w-lh-cap);
  font-variant-numeric: tabular-nums;
  display: flex; flex-direction: column; gap: var(--w-g-tight);
  -webkit-mask:
    conic-gradient(from 135deg at 50% 0, black 90deg, transparent 0) top / var(--hf-tooth) var(--hf-depth) repeat-x,
    linear-gradient(black, black) center / 100% calc(100% - 2 * var(--hf-depth)) no-repeat,
    conic-gradient(from -45deg at 50% 100%, black 90deg, transparent 0) bottom / var(--hf-tooth) var(--hf-depth) repeat-x;
  mask:
    conic-gradient(from 135deg at 50% 0, black 90deg, transparent 0) top / var(--hf-tooth) var(--hf-depth) repeat-x,
    linear-gradient(black, black) center / 100% calc(100% - 2 * var(--hf-depth)) no-repeat,
    conic-gradient(from -45deg at 50% 100%, black 90deg, transparent 0) bottom / var(--hf-tooth) var(--hf-depth) repeat-x;
}
.hf-receipt__head { display: flex; flex-direction: column; gap: var(--sp-2); text-align: center; font-family: var(--font); }
.hf-receipt__brand { font-size: var(--w-fs-h3); font-weight: var(--fw-bold); letter-spacing: var(--w-ls-h3); }
.hf-receipt__row { display: flex; align-items: baseline; gap: var(--w-g-inline); }
/* The leader: a dotted line that fills whatever space the label and the amount leave. */
.hf-receipt__row::before { content: ''; order: 1; flex: 1; border-bottom: var(--w-receipt-rule) dotted var(--faint); transform: translateY(calc(-1 * var(--sp-2))); }
.hf-receipt__row > :last-child { order: 2; }
.hf-receipt__rule { border: var(--sp-0); border-top: var(--w-receipt-rule) dashed var(--ink); margin: var(--sp-0); }
.hf-receipt__total { display: flex; align-items: baseline; justify-content: space-between; gap: var(--w-g-sibling); font-family: var(--font); font-weight: var(--fw-semibold); }
.hf-receipt__total .hf-fig { font-size: var(--font-money-min); }
.hf-receipt__note { font-family: var(--font); color: var(--mute); text-align: center; text-wrap: balance; }

/* ------------------------------------------------------------------- chat */
/* The WhatsApp conversation, drawn. It is the one screen that is not in the app, so it is
   built here from the product's own bubble tokens rather than captured. */
.hf-chat {
  display: flex; flex-direction: column; gap: var(--c-bubble-gap);
  width: min(100%, var(--c-device-w));
  padding: var(--w-g-sibling);
  border-radius: var(--r-xl);
  background: var(--w-panel);
}
.hf-bubble {
  max-width: var(--c-bubble-max);
  padding: var(--c-bubble-py) var(--c-bubble-px);
  border-radius: var(--c-bubble-r);
  font-size: var(--w-fs-body); line-height: var(--w-lh-lead);
  align-self: flex-start;
  background: var(--c-bubble-bg); color: var(--c-bubble-fg);
}
/* What you typed: the accent as a surface, ink on it. */
.hf-bubble--me { align-self: flex-end; background: var(--lime-500); color: var(--ink); border-end-end-radius: var(--r-xs); }
/* What the Guru answered: the product's money bubble. */
.hf-bubble--guru { background: var(--c-bubble-money-bg); color: var(--c-bubble-money-fg); border-end-start-radius: var(--r-xs); }
.hf-bubble--guru b { color: var(--lime-500); font-weight: var(--fw-semibold); }
.hf-typing { display: inline-flex; gap: var(--sp-4); align-items: center; min-height: var(--sp-20); }
.hf-typing i { width: var(--w-typing-dot); height: var(--w-typing-dot); border-radius: var(--r-pill); background: currentColor; opacity: .3; animation: hf-type var(--w-t-type) var(--w-ease) infinite; }
.hf-typing i:nth-child(2) { animation-delay: calc(var(--w-t-type) / 6); }
.hf-typing i:nth-child(3) { animation-delay: calc(var(--w-t-type) / 3); }
@keyframes hf-type { 0%, 60%, 100% { opacity: .3; } 30% { opacity: 1; } }

/* ---------------------------------------------------------------- marquee */
.hf-marquee { overflow: clip; display: flex; }
.hf-marquee__track {
  display: flex; flex: none; align-items: center; gap: var(--w-g-group);
  padding-inline-end: var(--w-g-group);
  min-width: 100%;
  animation: hf-slide var(--hf-marquee-d, var(--w-t-marquee)) linear infinite;
}
.hf-marquee[data-dir="right"] .hf-marquee__track { animation-direction: reverse; }
.hf-marquee__item { display: inline-flex; align-items: center; gap: var(--w-g-group); white-space: nowrap; }
.hf-marquee__item::after { content: ''; width: var(--w-tag-dot); height: var(--w-tag-dot); border-radius: var(--r-pill); background: currentColor; flex: none; }
@keyframes hf-slide { to { transform: translateX(-100%); } }

/* ------------------------------------------------------------------- said */
/* "Things you have definitely said." A speech bubble, not a testimonial: it has no name on it. */
.hf-said {
  display: inline-block;
  padding: var(--sp-24) var(--sp-28);
  border-radius: var(--r-lg); border-end-start-radius: var(--r-xs);
  background: var(--w-panel); color: var(--w-fg);
  font-size: var(--w-fs-h3); font-weight: var(--w-fw-h3); line-height: var(--w-lh-h3); letter-spacing: var(--w-ls-h3);
  max-width: var(--w-measure-lead);
  transform: rotate(var(--hf-rot, var(--w-sticker-rot-2)));
}
.hf-said--accent { background: var(--w-accent); color: var(--w-on-accent); }

/* ------------------------------------------------------------------ price */
.hf-price {
  display: flex; flex-direction: column; gap: var(--w-g-group);
  padding: var(--sp-32);
  border-radius: var(--r-xl);
  background: var(--w-bg); color: var(--w-fg);
}
.hf-price__head { display: flex; flex-direction: column; gap: var(--w-g-tight); }
.hf-price__amount { display: flex; align-items: baseline; gap: var(--w-g-tight); flex-wrap: wrap; }
.hf-price__list { display: flex; flex-direction: column; gap: var(--w-g-tight); }
.hf-price__list li { display: flex; align-items: baseline; gap: var(--w-g-tight); }
.hf-price__list .hf-icon { transform: translateY(var(--sp-2)); }

/* -------------------------------------------------------------------- faq */
.hf-faq { border-top: var(--w-stroke) solid var(--w-line); }
.hf-faq:last-of-type { border-bottom: var(--w-stroke) solid var(--w-line); }
.hf-faq > summary {
  display: flex; align-items: center; justify-content: space-between; gap: var(--w-g-sibling);
  min-height: var(--w-btn-h); padding-block: var(--w-g-sibling);
  cursor: pointer; list-style: none;
}
.hf-faq > summary::-webkit-details-marker { display: none; }
.hf-faq__sign {
  display: grid; place-items: center; flex: none;
  width: var(--w-touch); height: var(--w-touch); border-radius: var(--r-pill);
  background: var(--w-well);
  transition: transform var(--w-t-fast) var(--w-ease), background var(--w-t-fast) var(--w-ease);
}
.hf-faq[open] .hf-faq__sign { transform: rotate(45deg); background: var(--w-accent); color: var(--w-on-accent); }
.hf-faq__answer { padding-bottom: var(--w-g-group); color: var(--w-quiet); }

/* ------------------------------------------------------------------ field */
.hf-field { display: flex; flex-direction: column; gap: var(--w-g-tight); width: min(100%, var(--c-device-w)); }
.hf-field__label { font-size: var(--w-fs-label); font-weight: var(--w-fw-label); }
.hf-field__input {
  min-height: var(--w-field-h); padding: var(--w-field-pad);
  border: var(--sp-0); border-radius: var(--r-pill);
  background: var(--raised); color: var(--ink);
  font-size: var(--w-fs-body);
  box-shadow: inset 0 0 0 var(--w-stroke) var(--faint);
  transition: box-shadow var(--w-t-fast) var(--w-ease);
}
.hf-field__input::placeholder { color: var(--mute); opacity: 1; }
@media (hover: hover) and (pointer: fine) { .hf-field__input:hover { box-shadow: inset 0 0 0 var(--w-stroke) var(--ink); } }
.hf-field__input:focus-visible { outline-offset: var(--sp-0); border-radius: var(--r-pill); box-shadow: inset 0 0 0 var(--w-stroke) var(--ink); }
.hf-field__input:disabled { background: var(--field); color: var(--mute); cursor: not-allowed; }
.hf-field__input[aria-invalid="true"] { box-shadow: inset 0 0 0 var(--w-focus-w) var(--danger); }
/* A field that is a choice. The browser's own arrow sits wherever the browser likes, which in
   a pill is against the curve, so the arrow is ours: the menu's caret, clear of the edge. */
.hf-select { position: relative; display: block; }
.hf-select > select { appearance: none; width: 100%; padding-inline-end: var(--w-btn-seat); cursor: pointer; }
.hf-select > .hf-icon { position: absolute; inset-block: var(--sp-0); inset-inline-end: var(--sp-16); display: grid; place-items: center; font-size: var(--i-sm); pointer-events: none; }
.hf-field__hint { font-size: var(--w-fs-cap); color: var(--w-quiet); display: flex; align-items: center; gap: var(--w-g-inline); }
/* What stands under a field when there is more than its hint: the hint, and a link beside it. */
.hf-field__foot { display: flex; flex-wrap: wrap; align-items: center; gap: var(--w-g-tight) var(--w-g-control); }
/* The link is a thing to press on its own, not a word in a sentence, so it is given the height
   a press needs. */
.hf-field__foot .hf-link { display: inline-flex; align-items: center; min-height: var(--sp-24); }
/* An error is never colour alone: it has an icon and a sentence that says how to fix it. */
.hf-field__hint--error { color: var(--danger); background: var(--danger-tint); padding: var(--sp-8) var(--sp-12); border-radius: var(--r-sm); }
.hf-field__hint--done { color: var(--ink); background: var(--lime-100); padding: var(--sp-8) var(--sp-12); border-radius: var(--r-sm); }

/* ------------------------------------------------------------------- guru */
.hf-guru { display: block; flex: none; }
.hf-guru--hero   { width: var(--w-guru-hero);   height: var(--w-guru-hero); }
.hf-guru--mark   { width: var(--w-guru-mark);   height: var(--w-guru-mark); }
.hf-guru--voice  { width: var(--w-guru-voice);  height: var(--w-guru-voice); }
/* Inside a headline, standing where a word-space would be. It is sized in em, so it grows
   with the line, and it sits on the baseline's optical centre rather than on the baseline. */
.hf-guru--inline { display: inline-block; width: var(--w-guru-inline); height: var(--w-guru-inline); vertical-align: -0.12em; }

/* ----------------------------------------------------------------- reveal */
/* NOTHING IS HIDDEN UNLESS THE SCRIPT THAT WILL SHOW IT IS RUNNING. Every waiting state below
   is scoped to .hf-motion, a class one inline line in the <head> puts on <html> and takes off
   again if the page's script has not reported in. With no script, a failed script or a blocked
   one, the page is simply all there. A reveal is an enhancement, never a gate on the content.

   A LINE RISES INTO PLACE. The outer clips; the inner travels its own height. The outer is
   never at opacity 0, so the text is in the document and paintable from the first frame -
   an invisible hero is what moves the largest paint to the end of the animation. */
.hf-line { display: block; overflow: clip; padding-bottom: var(--w-mark-bleed-x); margin-bottom: calc(-1 * var(--w-mark-bleed-x)); }
.hf-line__in {
  display: block;
  transition: transform var(--w-t-reveal) var(--w-ease-out);
  transition-delay: calc(var(--hf-i, 0) * var(--w-stagger-line));
}
.hf-motion [data-reveal="wait"] .hf-line__in { transform: translateY(var(--w-rise)); }

/* A BLOCK RISES A LITTLE AND ARRIVES. For cards and paragraphs, where clipping would cut. */
.hf-rise { transition: transform var(--w-t-reveal) var(--w-ease-out), opacity var(--w-t-med) var(--w-ease); transition-delay: calc(var(--hf-i, 0) * var(--w-stagger-card)); }
.hf-motion [data-reveal="wait"] .hf-rise { transform: translateY(var(--w-rise-soft)); opacity: 0; }

/* A PARAGRAPH THAT READS ITSELF AS YOU SCROLL. Each word is quiet until the scroll reaches it.
   The script sets --hf-p from 0 to 1 per word; with no script every word is simply lit. */
.hf-flow { font-size: var(--w-fs-h2); line-height: var(--w-lh-h3); letter-spacing: var(--w-ls-h2); font-weight: var(--w-fw-h2); max-width: var(--w-measure); text-wrap: pretty; }
.hf-flow > span { opacity: calc(.22 + .78 * var(--hf-p, 1)); }

/* ----------------------------------------------------------------- cursor */
/* A POINTER WITH A FACE. Hidden until the script has seen a real mouse move, so a page whose
   script fails keeps the system cursor, which is the only correct fallback. */
.hf-cursor { position: fixed; top: var(--sp-0); left: var(--sp-0); z-index: var(--w-z-cursor); pointer-events: none; display: none; }
html.has-cursor .hf-cursor { display: block; }
html.has-cursor, html.has-cursor :where(a, button, summary, label, canvas, [data-drag], [data-cursor]) { cursor: none; }
/* Where precision or text entry matters, the system cursor comes back. */
html.has-cursor :where(input, textarea, select, [contenteditable="true"], [data-cursor="native"]) { cursor: auto; }

/* THE STACK, from the outside in. Each layer has exactly one owner, so the script and the
   stylesheet never write the same transform and never fight over it:

     __at     the script   where the pointer is. No easing, ever: the tip is the hotspot.
     __lean   the script   the swing behind the movement, turning about the tip.
     __body   the sheet    the mood's pose, about the tip.
     __face   the script   the eyes leading toward the direction of travel.
     __eyes   the sheet    the blink.
     __eye    the sheet    the mood's eye shape, and its two lids. */
.hf-cursor__at, .hf-cursor > .hf-cursor__tab { position: absolute; top: var(--sp-0); left: var(--sp-0); will-change: transform; }
.hf-cursor__lean { display: block; transform-origin: 0 0; }

/* The body: a drop. Round, with one sharp corner at the top left, and that corner is the tip.
   The white ring is a sticker's die-cut edge, so it reads over a dark button as well as paper;
   the shadow is the sticker's, because a cursor is the layer above the page by definition. */
.hf-cursor__body {
  display: grid; place-items: center; flex: none;
  width: var(--w-cursor-size); height: var(--w-cursor-size);
  border-radius: var(--w-cursor-tip) 50% 50% 50%;
  /* The lids below are larger than the eyes they cover. The body clips them, and because they
     are the body's own colour the clipped edge cannot be seen. */
  overflow: hidden;
  background: var(--w-cursor);
  box-shadow: 0 0 0 var(--w-cursor-edge) var(--raised), var(--w-sticker-shadow);
  transform-origin: 0 0;
  scale: var(--w-pose-scale, 1);
  rotate: var(--w-pose-turn, 0deg);
  transition: scale var(--w-t-fast) var(--w-spring), rotate var(--w-t-fast) var(--w-spring), opacity var(--w-t-fast) var(--w-ease);
}
.hf-cursor__face { display: block; }
.hf-cursor__eyes { display: flex; gap: var(--w-cursor-eye-gap); animation: hf-blink var(--w-t-blink) var(--w-ease) infinite; }
@keyframes hf-blink { 0%, 93%, 100% { scale: 1 1; } 96.5% { scale: 1 .1; } }

/* An eye is a pill with two lids over it, both the colour of the body. The upper one drops for
   sleep. The lower one is a round cheek that rises for a smile, which is what turns a pill into
   an arc. Both move by transform alone.

   THE LIDS ARE WIDER THAN THE EYE, ON PURPOSE. A lid clipped to the eye's own outline shares
   that outline's soft edge, and a hairline of the eye colour shows through all the way round it.
   A lid that overhangs covers the edge with its middle instead, and there is nothing to see. */
.hf-cursor__eye {
  position: relative; display: block;
  width: var(--w-cursor-eye-w); height: var(--w-cursor-eye-h);
  border-radius: var(--r-pill);
  background: var(--w-on-cursor);
  scale: var(--w-pose-eye, 1);
  transition: scale var(--w-t-fast) var(--w-spring);
}
/* One eye can be told apart from the other: that is a wink. */
.hf-cursor__eye:first-child { scale: var(--w-pose-eye-left, var(--w-pose-eye, 1)); }
.hf-cursor__eye::before, .hf-cursor__eye::after {
  content: ''; position: absolute; background: var(--w-cursor);
  transition: transform var(--w-t-fast) var(--w-ease);
}
.hf-cursor__eye::before { left: -40%; width: 180%; top: -20%; height: 120%; transform: translateY(var(--w-pose-lid, -100%)); }
.hf-cursor__eye::after { left: -50%; top: 100%; width: 200%; aspect-ratio: 1; border-radius: 50%; transform: translateY(var(--w-pose-cheek, 0%)); }

/* The tab: one word, naming what a tap will do. It sits beside the body, clear of the tip. */
.hf-cursor__tab {
  display: inline-flex; align-items: center; flex: none;
  min-height: var(--w-cursor-tab-h); padding: var(--w-cursor-tab-pad);
  border-radius: var(--r-pill); border-start-start-radius: var(--r-xs);
  background: var(--w-cursor); color: var(--w-on-cursor);
  box-shadow: 0 0 0 var(--w-cursor-edge) var(--raised);
  font-size: var(--w-fs-cap); font-weight: var(--fw-bold); line-height: var(--w-lh-label); white-space: nowrap;
}
.hf-cursor > .hf-cursor__tab {
  margin: calc(var(--w-cursor-size) / 2) 0 0 calc(var(--w-cursor-size) + var(--w-cursor-tab-gap));
  opacity: 0; scale: .8; transform-origin: top left;
  transition: opacity var(--w-t-fast) var(--w-ease), scale var(--w-t-fast) var(--w-spring);
}
.hf-cursor[data-tab="true"] > .hf-cursor__tab { opacity: 1; scale: 1; }
/* Over a field, or outside the window, it steps aside completely. */
.hf-cursor[data-mood="away"] .hf-cursor__body, .hf-cursor[data-mood="away"] > .hf-cursor__tab { opacity: 0; }

/* THE SAME OBJECT, FOR A PERSON WHO IS NOT YOU: a flatmate in the Rooms scene, or a mood shown
   standing still on the specimen page. It takes the same data-mood the live cursor does. */
.hf-actor {
  position: absolute; top: var(--sp-0); left: var(--sp-0);
  display: inline-flex; align-items: flex-start; gap: var(--w-cursor-tab-gap);
  pointer-events: none; z-index: var(--w-z-sticker);
}
.hf-actor--still { position: relative; z-index: auto; }
.hf-actor .hf-cursor__tab { margin-top: calc(var(--w-cursor-size) / 2); }
/* Each person in a Room has their own colours. Three bodies, all measured pairs. */
.hf-actor--ink   { --w-cursor: var(--dark);     --w-on-cursor: var(--lime-500); }
.hf-actor--lime  { --w-cursor: var(--lime-500); --w-on-cursor: var(--ink); }
.hf-actor--paper { --w-cursor: var(--surface);  --w-on-cursor: var(--ink); }

/* ---------------------------------------------------------- reduced motion */
/* Fewer and gentler, not none. Movement becomes a fade; anything that loops, stops; anything
   that was waiting to arrive is simply there. */
@media (prefers-reduced-motion: reduce) {
  .hf-line__in, .hf-rise, .hf-mark::before { transition-duration: var(--w-t-fast); transition-delay: 0s; }
  .hf-motion [data-reveal="wait"] .hf-line__in { transform: none; }
  .hf-motion [data-reveal="wait"] .hf-rise { transform: none; }
  .hf-marquee { overflow-x: auto; }
  .hf-marquee__track { animation: none; }
  .hf-typing i { animation: none; opacity: .6; }
  .hf-btn, .hf-btn__seat, .hf-btn__seat .hf-icon { transition: none; }
  .hf-flow > span { opacity: 1; }
  /* The cursor keeps its moods, because they are information. It stops blinking. */
  .hf-cursor__eyes { animation: none; }
}

/* Forced colours: the system draws the page. The custom cursor would be an unreadable guess. */
@media (forced-colors: active) {
  html.has-cursor, html.has-cursor * { cursor: auto; }
  html.has-cursor .hf-cursor { display: none; }
}
