/* NIX — the site in the Blank's design (Hector, 2026-10-02).
   Ported from the Design Studio prototype (prototypes/nix-website/layer.css),
   where it was drawn and approved page by page. Loaded LAST: after the page
   sheet on the standalone pages (head.xml) and after Odoo's frontend bundle on
   the portal leg (portal/layout.xml), because it is the word that wins.
   The DS tokens it reads (--text, --text-muted, --surface-*, --state-hover)
   come from ds-tokens.css, linked right after tokens.css. */

/* THE DS's TYPEFACE, SAID AGAIN. On the portal leg (the blog, the sign-in, the
   account) Odoo's frontend bundle comes after ds-tokens.css and declares its
   own --font on :root, Inter, and everything the Blank sets in var(--font)
   turned into Inter there. This sheet comes after the bundle, so it says the
   DS's once more (Hector, 2026-10-03). */
:root { --font: "PP Neue Montreal", system-ui, -apple-system, sans-serif; }

/* Essentials: shell.css places .index/.page/.mk in the panel column but not
   .es-panel, so the store fell into the 0px rail track (7 pages, 24px wide).
   Same bug on the live addon; fixed here, not in views/nix-website/. */
.nav-shell > .es-panel { grid-column: 2; }

/* ── Full width: no card round the content ─────────────────────────────────
   Every page's scroller (.index, .page, .es-panel) was a card: the panel
   ground, a 20px radius, and an 8px inset of paper round it (.nav-shell's
   padding, which is --shell-gap). The gap goes to zero — the token, so the
   fixed pieces placed off the same edge (the logo, the section bars) follow
   the content to the edge — and the corners go square. The panel keeps its
   ground, so what sits on it keeps its contrast. */
:root { --shell-gap: 0px; }
main.index, main.page, main.es-panel { border-radius: 0; }
body .index-foot { border-radius: 0; }

/* ── The ground, the Blank's ───────────────────────────────────────────────
   The scrollers above still painted --nix-panel (#161616 / #FAFAFA) on a body
   of --nix-paper (#101010 / #F5F5F5): square and edge to edge it read as the
   page, but the menu scales the page to .94 and the paper showed round it —
   the card again, drawn by the step between the two. The Blank has no such
   step: its views paint nothing and what is behind them is .ti-bg, a still
   gradient on its own three tokens. So here: the same tokens (day / night
   are this site's light / dark), the same gradient on the body, fixed to the
   window so it stays put while the page recedes, and the scrollers clear. */
:root {
  --ti-bg-top: #f4f4f2; --ti-bg-mid: #ebebe8; --ti-bg-low: #dfe0de;
}
html[data-theme="dark"] {
  --ti-bg-top: #1b1c1e; --ti-bg-mid: #141516; --ti-bg-low: #0e0f10;
}
html, body { background-color: var(--ti-bg-low); }
body { background: linear-gradient(180deg, var(--ti-bg-top) 0%, var(--ti-bg-mid) 55%, var(--ti-bg-low) 100%) fixed; }
main.index, main.page, main.es-panel { background: transparent; }
/* What painted itself in the panel's colour to vanish into it (Business AI v3's
   stuck stage, the logo discs, Agent Base's menus and phone) takes the
   gradient's middle. */
:root, html[data-theme="dark"] { --nix-panel: var(--ti-bg-mid); }
/* ECH0's hero has no light of its own any more: no blue, no gradient — it
   stands on the page's ground like everything else, in both themes. */
.voice__field[data-host=".voice__hero"],
html:not([data-theme="dark"]) .voice__field[data-host=".voice__hero"] { background: none; }

/* ── The menu, the Blank prototype's way ───────────────────────────────────
   Opening it is a depth move: the page steps back (smaller, softer, dimmer)
   and the menu words fade in sharp in front of it, one by one. Built by
   layer.js as .ti-chrome on every page that had a menu; html.ti-site carries
   the state (is-open, is-peek, is-peek-out, is-profile-open). Tokens are the
   Blank's, pointed at the landing's palette so both themes follow. */
html.ti-site {
  --ti-ink: var(--nix-text);
  --ti-ink-soft: color-mix(in srgb, var(--nix-text) 55%, transparent);
  --ti-hover: color-mix(in srgb, var(--nix-text) 5%, transparent);
  --ti-track: color-mix(in srgb, var(--nix-text) 8%, transparent);
  --ti-knob: var(--nix-text);
  --ti-ease: cubic-bezier(.2,.7,.2,1);
}

/* The menus it replaces: the card (.vmenu), its ring, and the rails Business
   AI and the account still wore. The markup stays; only this layer stops
   drawing it. NOT WAITING FOR html.ti-site: that class comes from blank.js,
   which is deferred, and until it ran the old ring and rail were drawn and
   then vanished on a slow load (Hector, 2026-10-03). The sheet hides them
   from the first paint; the Blank's button arrives with the script. */
.site-menu__trigger,
.vmenu,
.nav-shell > .nav-rail,
.rail-grip { display: none !important; }
body { --rail-track: 0px; --rail-gap: 0px; }

.ti-chrome { position: fixed; inset: 0; z-index: 1000; pointer-events: none;
  font-family: var(--font-sans); font-weight: 300; color: var(--ti-ink); }
.ti-chrome > * { pointer-events: auto; }

/* Depth: the page recedes while the menu is open. Everything in <body> but
   the menu itself; the origin is set on the visible part of the page. */
html.ti-site body > :not(.ti-chrome) {
  transition: transform 650ms var(--ti-ease), filter 450ms ease, opacity 450ms ease;
  transform-origin: 60% var(--ti-origin-y, 50vh);
}
html.ti-site.is-open body > :not(.ti-chrome) { transform: scale(.94); filter: blur(5px); opacity: .45; }

/* Changing page: the page leaving fades and blurs out, the one arriving fades
   and blurs in (the Blank's view switch, across documents). */
html.ti-site.is-leaving body > :not(.ti-chrome) { opacity: 0; filter: blur(10px); pointer-events: none; }
html.ti-site.is-entering body > :not(.ti-chrome) { opacity: 0; filter: blur(10px); transition: none; }

/* Menu: three staggered lines, left-aligned. Hover evens them; open makes an X. */
.ti-menu { position: absolute; left: 40px; top: 23px; z-index: 4; width: 26px; height: 18px; padding: 0; background: none; border: 0; cursor: pointer;
  transform-origin: 60% 50%; transition: opacity 450ms ease, transform 650ms var(--ti-ease), filter 450ms ease; }
.ti-menu span { position: absolute; left: 0; height: 1.5px; border-radius: 2px; background: var(--ti-ink);
  transition: width 350ms var(--ti-ease), transform 350ms var(--ti-ease), top 350ms var(--ti-ease), opacity 200ms ease, background 600ms ease; }
.ti-menu span:nth-child(1) { top: 2px;  width: 16px; }
.ti-menu span:nth-child(2) { top: 8px;  width: 26px; }
.ti-menu span:nth-child(3) { top: 14px; width: 16px; }
.ti-menu:hover span { width: 26px; }
.ti-menu[aria-expanded="true"] span:nth-child(1) { top: 8px; width: 24px; transform: rotate(45deg); }
.ti-menu[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.ti-menu[aria-expanded="true"] span:nth-child(3) { top: 8px; width: 24px; transform: rotate(-45deg); }
.ti-menu:focus-visible { outline: 1px solid var(--ti-ink-soft); outline-offset: 6px; border-radius: 4px; }
/* Open, the button fades away under the blur; a tap outside (or Esc) closes. */
html.is-open .ti-menu { opacity: 0; pointer-events: none; transform: scale(.94); filter: blur(5px); }

.ti-veil { position: absolute; inset: 0; z-index: 3; pointer-events: none; }
html.is-open .ti-veil { pointer-events: auto; }

/* Menu words: on top of the blur, one by one after the sweep. */
.ti-nav { position: absolute; z-index: 4; left: 40px; top: 17px; display: flex; flex-direction: column; gap: 14px;
  transform-origin: 0 50%; transition: transform 650ms var(--ti-ease), filter 450ms ease, opacity 450ms ease; }
.ti-nav[hidden] { display: none; }
.ti-nav a { font-family: var(--font-sans); font-weight: 400; font-size: 18px; letter-spacing: .14em; text-transform: uppercase; line-height: 1.2;
  color: var(--ti-ink-soft); text-decoration: none; opacity: 0; animation: ti-in 450ms ease forwards; transition: color 250ms ease; }
.ti-nav a:nth-child(1) { animation-delay: 250ms; }
.ti-nav a:nth-child(2) { animation-delay: 310ms; }
.ti-nav a:nth-child(3) { animation-delay: 370ms; }
.ti-nav a:nth-child(4) { animation-delay: 430ms; }
.ti-nav a:nth-child(5) { animation-delay: 490ms; }
.ti-nav a:nth-child(6) { animation-delay: 550ms; }
.ti-nav a:hover, .ti-nav a:focus-visible, .ti-nav a[aria-current="page"] { color: var(--ti-ink); outline: none; }
@keyframes ti-in { to { opacity: 1; } }
/* With the profile menu open, the words recede too. */
html.is-profile-open .ti-nav { transform: scale(.94); filter: blur(5px); opacity: .45; pointer-events: none; }

/* Profile: a circle and a word, bottom-left, shown only while the menu is open. */
.ti-profile { position: absolute; left: 40px; bottom: 36px; z-index: 4; display: flex; align-items: center; gap: 12px;
  padding: 0; border: 0; background: none; color: var(--ti-ink-soft); cursor: pointer; opacity: 0; pointer-events: none;
  transition: color 250ms ease, opacity 450ms ease; }
.ti-avatar { width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center; background: var(--ti-ink); color: var(--ti-bg-top);
  transition: background 600ms ease, color 600ms ease; }
.ti-avatar svg { width: 14px; height: 14px; }
.ti-name { font-family: var(--font-sans); font-size: 13px; letter-spacing: .14em; text-transform: uppercase; }
.ti-profile:hover, .ti-profile:focus-visible { color: var(--ti-ink); outline: none; }
html.is-open .ti-profile { opacity: 1; pointer-events: auto; transition-delay: 0ms, 450ms; }

/* The profile menu floats above the name; its rows rise one after another. */
.ti-profile-menu { position: absolute; left: 28px; bottom: 76px; z-index: 40; display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  opacity: 0; pointer-events: none; transform-origin: bottom left; }
.ti-profile-menu[hidden] { display: none; }
.ti-profile-menu.is-open { opacity: 1; pointer-events: auto; }
.ti-act { display: flex; align-items: center; gap: 12px; border: 0; background: none; cursor: pointer; font: inherit; font-size: 16px; text-align: left; white-space: nowrap;
  color: var(--ti-ink-soft); padding: 7px 12px; margin: 0; border-radius: 10px; text-decoration: none;
  opacity: 0; transform: translateY(6px); transition: opacity 300ms ease, transform 360ms cubic-bezier(.22,1,.36,1), color 250ms ease; }
.ti-profile-menu.is-open .ti-act { opacity: 1; transform: none; transition-delay: calc(var(--j, 0) * 60ms + 30ms); }
.ti-act:hover, .ti-act:focus-visible { color: var(--ti-ink); outline: none; }
/* Theme: one more row, the word and the switch beside it. */
.ti-toggle-track { position: relative; width: 34px; height: 18px; border-radius: 999px; background: var(--ti-track); transition: background 300ms ease; }
.ti-toggle-knob { position: absolute; top: 3px; left: 3px; width: 12px; height: 12px; border-radius: 50%; background: var(--ti-knob);
  transition: translate 350ms var(--ti-ease), background 300ms ease; }
.ti-toggle[aria-checked="true"] .ti-toggle-knob { translate: 16px 0; }
/* Language: the site's own EN / ES buttons (the head binds them), drawn as words. */
.ti-lang { cursor: default; }
.ti-lang .lang__opt { all: unset; cursor: pointer; font-size: 13px; letter-spacing: .14em; color: var(--ti-ink-soft); transition: color 250ms ease; }
.ti-lang .lang__opt:hover, .ti-lang .lang__opt.is-on { color: var(--ti-ink); }
.ti-lang .lang__opt:focus-visible { outline: 1px solid var(--ti-ink-soft); outline-offset: 4px; border-radius: 2px; }
.ti-lang-sep { color: var(--ti-ink-soft); font-size: 13px; }

/* Peek: after choosing a place the page comes forward, but the words stay for
   6 s; the button is hidden until they go. */
html.is-peek .ti-menu { opacity: 0; pointer-events: none; }
html.is-peek .ti-nav a { animation: none; opacity: 1; transition: opacity 450ms ease, color 250ms ease; }
html.is-peek-out .ti-nav a { opacity: 0; pointer-events: none; }
html.is-peek-out .ti-menu { opacity: 1; pointer-events: auto; transition: opacity 450ms ease 250ms; }

@media (prefers-reduced-motion: reduce) {
  .ti-nav a, .ti-act { animation: none; opacity: 1; transition: none; }
  html.ti-site body > :not(.ti-chrome) { transition: none; }
}

/* Phone: the button and the words move in to the 24px edge. */
@media (max-width: 560px) {
  .ti-menu { left: 24px; }
  .ti-nav { left: 24px; top: 66px; }
  .ti-profile { left: 24px; }
  .ti-profile-menu { left: 12px; }
}

/* ── Agent Base (ECH0) in the light theme ──────────────────────────────────
   Dark keeps what it has. In light the page's "objects with their own light"
   went pale → near black: the hero was a dark band floating between a white
   top and a white bottom, and every card frame ended in black. Light gets
   its own daylight versions, same hues. */

/* The hero's words go back to the theme's own ink in light (the dark-theme
   rule pinned them light), and with them the buttons and the pointer's wake. */
html:not([data-theme="dark"]) .voice__field[data-host=".voice__hero"] { color: var(--nix-text); }
html:not([data-theme="dark"]) .voice__hero {
  --nix-text: inherit;
  --nix-text-soft: inherit;
  --nix-ink: inherit;
  --nix-on-ink: inherit;
}


/* ── The blog, in the current DS ──────────────────────────────────────────
   One reading column, the Studio's DS tokens (--text, --text-muted,
   --state-hover, --font) and the Blank's patterns: the index is a list of rows
   (title and line on the left, the date as a small caps meta on the right,
   the row easing inward under the pointer), a post is its title, one line of
   facts and the text, in the same column. No header, no tags, no filter bar;
   blog.css's cards and masthead are not used here. */
#wrapwrap .website_blog.nix-col {
  width: min(640px, 100%); margin: 0 auto; box-sizing: border-box;
  padding: 96px var(--space-3) 96px; font-family: var(--font); color: var(--text);
}

/* The index: rows, no lines between them (a line means an editable field). */
.nix-rows { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
/* The hover moves nothing but the row under the pointer: its fill is a layer
   of its own (::before, faded in) and the inward ease is a transform of its
   contents, so no row's box changes and no neighbour is re-laid out. Only on
   a device that hovers: a tap on a phone must not leave a row lit. */
#wrapwrap .nix-row {
  position: relative; display: flex; justify-content: space-between; align-items: baseline; gap: 20px;
  padding: 14px 0; color: var(--text); text-decoration: none; cursor: pointer;
}
#wrapwrap .nix-row::before { content: ""; position: absolute; inset: 0 -12px; border-radius: var(--radius-sm);
  background: var(--state-hover); opacity: 0; transition: opacity 200ms ease; pointer-events: none; }
#wrapwrap .nix-row > * { position: relative; transition: transform 220ms cubic-bezier(.2, .7, .2, 1), color 200ms ease; }
@media (hover: hover) {
  #wrapwrap .nix-row:hover::before { opacity: 1; }
  #wrapwrap .nix-row:hover .nix-row__main { transform: translateX(4px); }
  #wrapwrap .nix-row:hover .nix-row__meta { transform: translateX(-4px); }
}
#wrapwrap .nix-row:focus-visible { outline: none; }
#wrapwrap .nix-row:focus-visible::before { opacity: 1; }
.nix-row__main { display: grid; gap: 4px; min-width: 0; }
.nix-row__title { font-size: 17px; font-weight: 400; line-height: 1.35; }
.nix-row__sub { font-size: 14px; line-height: 1.45; color: var(--text-muted); }
.nix-row__meta { flex: none; font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--text-muted); white-space: nowrap; transition: color 200ms ease; }
@media (hover: hover) { #wrapwrap .nix-row:hover .nix-row__meta { color: var(--text); } }

/* A post: the way back, the title, its line, then the text. */
:is(#wrapwrap, .blog-layer) .nix-art__title { margin: 0; font-size: clamp(28px, 4.4vw, 38px); font-weight: 300; line-height: 1.12; letter-spacing: -0.02em; color: var(--text); text-wrap: balance; }
:is(#wrapwrap, .blog-layer) .nix-art .nix-art__sub { margin: 14px 0 0; font-size: 18px; line-height: 1.5; color: var(--text-muted); }
:is(#wrapwrap, .blog-layer) .nix-art .nix-art__meta { margin: 16px 0 40px; font-size: 13px; color: var(--text-muted); }
/* The facts as the Blank sets metadata: small caps, wide tracking, soft ink,
   the author first behind an initial (the Blank's avatar), and a fine dot
   with air between each — drawn, not typed, so it sits on the line's centre. */
:is(#wrapwrap, .blog-layer) .nix-art .nix-art__meta {
  display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 8px 16px;
  font-size: 11px; letter-spacing: .12em; text-transform: uppercase; line-height: 20px;
}
:is(#wrapwrap, .blog-layer) .nix-art .nix-art__meta > * + *::before {
  content: ""; display: inline-block; width: 3px; height: 3px; margin: 0 16px 0 0; border-radius: 50%;
  background: currentColor; opacity: .55; vertical-align: middle; transform: translateY(-1px);
}
.nix-art__by { display: inline-flex; align-items: center; gap: 8px; color: var(--text); }
.nix-art__avatar { flex: none; width: 20px; height: 20px; border-radius: 50%; display: grid; place-items: center;
  background: var(--text); color: var(--surface-page); font-size: 10px; letter-spacing: 0; }

:is(#wrapwrap, .blog-layer) .nix-art .o_wblog_post_content_field { font-size: 17px; color: var(--text); }
:is(#wrapwrap, .blog-layer) .nix-art p { margin: 0 0 1.15em; line-height: 1.7; color: var(--text); }
:is(#wrapwrap, .blog-layer) .nix-art h2,
:is(#wrapwrap, .blog-layer) .nix-art h3 { margin: 1.9em 0 .55em; font-size: 21px; font-weight: 400; line-height: 1.25; letter-spacing: -0.01em; color: var(--text); }
:is(#wrapwrap, .blog-layer) .nix-art h2 { font-size: 25px; }
:is(#wrapwrap, .blog-layer) .nix-art ul,
:is(#wrapwrap, .blog-layer) .nix-art ol { margin: 0 0 1.15em; padding-left: 1.3em; color: var(--text); }
:is(#wrapwrap, .blog-layer) .nix-art li { margin: .4em 0; line-height: 1.65; }
:is(#wrapwrap, .blog-layer) .nix-art li::marker { color: var(--text-muted); }
:is(#wrapwrap, .blog-layer) .nix-art .o_wblog_post_content_field a { color: var(--text); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: color-mix(in srgb, var(--text) 35%, transparent); }

/* The two arrows, as the DS draws a round control: a soft fill, no shadow. */
:is(#wrapwrap, .blog-layer) .nix-art__pager-wrap .nix-pager { justify-content: center; margin: 56px 0 0; gap: 8px; }
/* Only the chevrons: no round fill, the 38px stays as the tap target; soft
   ink, full ink under the pointer. */
:is(#wrapwrap, .blog-layer) .nix-art__pager-wrap .nix-pager__arrow { width: 38px; height: 38px; border-radius: 0; background: none; color: var(--text-muted); box-shadow: none; transition: color 180ms ease; }
:is(#wrapwrap, .blog-layer) .nix-art__pager-wrap .nix-pager__arrow:hover { background: none; color: var(--text); transform: none; }

/* ── A word for a mark ─────────────────────────────────────────────────────
   On ECH0's page and the blog the NIX logo at the top is the page's own name
   ("ECH0", "blog"), set like the Blank's header title: the site's face, light
   weight, wide tracking, on the menu button's row. Difference blending keeps
   it legible over whatever is under it — ECH0's pale hero top in dark, the
   ground in light — without a colour per theme. */
.nix-toplogo--word, #wrapwrap .nix-toplogo--word { top: 23px; line-height: 18px; mix-blend-mode: difference; text-decoration: none; }
.nix-toplogo__word { display: block; font-family: var(--font-sans); font-weight: 300; font-size: 18px;
  letter-spacing: .14em; color: #fff; white-space: nowrap; }
@media (max-width: 720px) { .nix-toplogo--word { top: 23px; } }
/* The Blank's header measures: titles 18px at .14em, centred on the header's
   middle line (32px down: the 54px head with its words at 32px), and the menu
   button on the same line (32 - 9 = 23px). */

/* ── The foot: the cipher on top, the mark and its words under it ─────────
   The bar was three columns (mark and words · cipher · social). Now one
   centred column at every width — the layout the phone already had — with
   the cipher first and the NIX mark, "© 2026 NIX" and Web access under it. */
.index-foot .index-foot__bar { grid-template-columns: 1fr; justify-items: center; text-align: center; row-gap: 14px; border-top: 0; }
.index-foot .index-foot__cipher { order: 1; }
.index-foot .index-foot__sign { order: 2; justify-content: center; }
.index-foot .index-foot__social { order: 3; }
.index-foot .index-foot__social:empty { display: none; }

/* ── ECH0's cards: no gradient, butterflies of their own colour ───────────
   The three fact cards and How it works' frame lose their pale-to-dark
   gradient for the DS's quiet card fill, and a few butterflies fly inside
   each one (layer.js draws them), in the card's own hue: bronze, sage,
   plum, rose. --fly is that hue, a tone per theme so it reads on the fill. */
.voice__facts .voice__fact-card,
.voice .hw .hw__frame { background: var(--surface-fill); position: relative; }
.voice__facts .voice__fact:nth-child(1) .voice__fact-card { --fly: #B8946A; }
.voice__facts .voice__fact:nth-child(2) .voice__fact-card { --fly: #7FA592; }
.voice__facts .voice__fact:nth-child(3) .voice__fact-card { --fly: #9C86BC; }
.voice .hw .hw__frame { --fly: #C08791; }
html:not([data-theme="dark"]) .voice__facts .voice__fact:nth-child(1) .voice__fact-card { --fly: #8A6A45; }
html:not([data-theme="dark"]) .voice__facts .voice__fact:nth-child(2) .voice__fact-card { --fly: #4F7563; }
html:not([data-theme="dark"]) .voice__facts .voice__fact:nth-child(3) .voice__fact-card { --fly: #6C5591; }
html:not([data-theme="dark"]) .voice .hw .hw__frame { --fly: #94535F; }
/* The flock flies behind the screen inside each card, and the screen is
   frosted glass over it: a translucent fill of the page's own surface and a
   blur, so the butterflies show through it, softened, under the content. */
.card-flock { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 0; pointer-events: none; display: block; }
.voice__facts .voice__fact-screen,
.voice .hw .hw__ui {
  position: relative; z-index: 1;
  background: color-mix(in srgb, var(--nix-surface) 38%, transparent);
  -webkit-backdrop-filter: blur(6px) saturate(1.3); backdrop-filter: blur(6px) saturate(1.3);
  box-shadow: 0 -10px 40px rgba(0, 0, 0, .18);
}

/* ── The pricing cards, the same way ───────────────────────────────────────
   The three plans lose their gradient for the DS card fill; a flock flies in
   each, in the plan's colour, behind the plan's inner panel (its ::before,
   at z-index -1 in the card's isolated stack, so the flock goes to -2); and
   that panel is frosted glass, so the flock shows through under the text. */
.voice__plans .voice__plan { background: var(--surface-fill); }
.voice__plans .voice__plan:nth-child(1) { --fly: #B8946A; }
.voice__plans .voice__plan:nth-child(2) { --fly: #7FA592; }
.voice__plans .voice__plan:nth-child(3) { --fly: #9C86BC; }
html:not([data-theme="dark"]) .voice__plans .voice__plan:nth-child(1) { --fly: #8A6A45; }
html:not([data-theme="dark"]) .voice__plans .voice__plan:nth-child(2) { --fly: #4F7563; }
html:not([data-theme="dark"]) .voice__plans .voice__plan:nth-child(3) { --fly: #6C5591; }
.voice__plans .voice__plan > .card-flock { z-index: -2; }
.voice__plans .voice__plan::before {
  background: color-mix(in srgb, var(--nix-surface) 38%, transparent);
  -webkit-backdrop-filter: blur(6px) saturate(1.3); backdrop-filter: blur(6px) saturate(1.3);
  box-shadow: 0 -10px 40px rgba(0, 0, 0, .18);
}
/* The lead plan (Lifetime) has an inverted panel — the theme's ink, with its
   words in the opposite colour — so its glass is made of ink, not surface. */
.voice__plans .voice__plan--lead::before { background: color-mix(in srgb, var(--nix-ink) 80%, transparent); }

/* ── A post opens in depth, the Blank's Blur Layer ────────────────────────
   From the list, a post is not a new page: the list steps back (smaller,
   blurred, almost gone) and the post floats up in front of it — the Blank's
   values: scale .94, blur 5px, .05 over 650ms behind; the card rising from
   14px below at .98 over 480ms. A tap outside the post, Esc or Back closes it.
   On a post opened by its own address, a tap outside the post goes to the
   list. No "back to blog" link any more. */
/* The step back is the menu's, exactly: the whole page as one piece (every
   child of <body> but the menu and this layer), about the same point, with
   the same scale, blur, opacity and timing — html.ti-site body > * already
   carries the transition and the origin (see "The menu"). */
/* Same move as the menu (scale, origin, timing); quieter behind a post than
   behind the menu's few words — a page of text is being read in front of it,
   so the list behind is blurred further and nearly gone. */
html.ti-site.is-post-open body > :not(.ti-chrome):not(.blog-layer) { transform: scale(.94); filter: blur(10px); opacity: .20; pointer-events: none; }
.blog-layer { position: fixed; inset: 0; z-index: 900; overflow-y: auto; display: flex; justify-content: center; align-items: flex-start;
  padding: 96px var(--space-3) 12vh; box-sizing: border-box; opacity: 0; pointer-events: none; transition: opacity 400ms ease; }
html.is-post-open .blog-layer { opacity: 1; pointer-events: auto; }
.blog-layer__card { width: min(640px, 100%); font-family: var(--font); color: var(--text); cursor: auto;
  transform: translateY(14px) scale(.98); transition: transform 480ms cubic-bezier(.22, 1, .36, 1); }
html.is-post-open .blog-layer__card { transform: none; }
@media (prefers-reduced-motion: reduce) {
  .blog-layer, .blog-layer__card { transition: none; }
}

/* ── The blog on the same ground as every other page ───────────────────────
   portal.css (the Odoo layout's sheet, loaded only by the blog) paints body
   and #wrapwrap a flat --nix-paper over the Blank's ground the rest of the
   site stands on. Same gradient here, and #wrapwrap clear. */
html body:has(.website_blog) { background: linear-gradient(180deg, var(--ti-bg-top) 0%, var(--ti-bg-mid) 55%, var(--ti-bg-low) 100%) fixed; }
html body:has(.website_blog) #wrapwrap { background: transparent; }
/* The arrows' own box, from blog.css (scoped to #wrapwrap), for the layer. */
.blog-layer .nix-pager__arrow { display: inline-flex; align-items: center; justify-content: center; text-decoration: none; }
/* A post's head — its title, its line and its facts — centred over the
   column; the text below stays ranged left, which is how a column reads. */
:is(#wrapwrap, .blog-layer) .nix-art .nix-art__title,
:is(#wrapwrap, .blog-layer) .nix-art .nix-art__sub,
:is(#wrapwrap, .blog-layer) .nix-art .nix-art__meta { text-align: center; }

/* ── ECH0 at the Blank's scale (html.ab-blank, on /agent-base) ──────────
   The same page, measured like the Blank: one narrow centred column
   (560px for words, 720px for pictures), type that whispers (300 weight,
   15px reading, 20px titles), section names set like the menu words
   (18px capitals, .14em tracking), no borders on the cards, 10px radii,
   pill buttons at 13px, and air (14vh) instead of boxes between sections. */
html.ab-blank {
  --ab-col: 560px; --ab-wide: 720px; --ab-gap: 14vh;
  --ab-line: color-mix(in srgb, var(--nix-text) 10%, transparent);
  --ab-soft: color-mix(in srgb, var(--nix-text) 55%, transparent);
}
html.ab-blank .voice { font-weight: 300; }
html.ab-blank .voice :is(h1, h2, h3, p, li) { font-weight: 300; }

/* Hero: a sentence, not a billboard, alone on a full screen. */
html.ab-blank .voice__hero { min-height: 100vh; min-height: 100dvh; box-sizing: border-box; display: flex; flex-direction: column; justify-content: center; align-items: center; padding: 0 24px; }
html.ab-blank .voice__lead { max-width: 640px; margin-inline: auto; font-size: clamp(30px, 4.2vw, 42px); line-height: 1.15; letter-spacing: -0.015em; }
html.ab-blank .voice__hero-sub { text-wrap: balance; max-width: 420px; margin: 18px auto 0; font-size: 15px; line-height: 1.55; color: var(--ab-soft); }
html.ab-blank .voice__cta { gap: 10px; margin-top: 32px; }
html.ab-blank .voice__btn, html.ab-blank .voice__plan-cta { padding: 10px 22px; min-height: 0; min-width: 0; width: auto; font-size: 13px; letter-spacing: .02em; border-radius: 999px; }
html.ab-blank .voice__btn-ico { width: 14px; height: 14px; }
html.ab-blank .voice__btn--outline { background: none; box-shadow: inset 0 0 0 1px var(--ab-line); }
html.ab-blank .voice__soon { font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--ab-soft); }

/* Section names: the menu's voice. */
html.ab-blank .voice__h { font-size: 18px; line-height: 1.2; letter-spacing: .14em; text-transform: uppercase; text-align: center; color: var(--nix-text); }

/* Why: one quiet paragraph in the column, right after the hero (the hero
   is a full screen already; the page's own 96px gap is the air between). */
html.ab-blank .voice__why { min-height: 0; padding: 0 24px var(--ab-gap); }
html.ab-blank .voice__why-text { max-width: var(--ab-col); margin: 28px auto 0; font-size: 17px; line-height: 1.6; letter-spacing: 0; text-align: center; color: var(--ab-soft); }

/* Facts: stacked and centred — the title, the picture, then the words
   under it (the copy box opens up so its two lines can sit either side). */
html.ab-blank .voice__facts { display: flex; flex-direction: column; align-items: center; gap: var(--ab-gap); padding: 0 24px var(--ab-gap); }
html.ab-blank .voice__fact { display: flex; flex-direction: column; align-items: center; gap: 20px; width: min(var(--ab-wide), 100%); }
html.ab-blank .voice__fact-copy { display: contents; }
html.ab-blank .voice__fact-h { order: 0; max-width: 420px; margin: 0 0 4px; text-align: center; font-size: 20px; line-height: 1.35; letter-spacing: 0; }
html.ab-blank .voice__fact:nth-child(n) .voice__fact-card { order: 1; }   /* over the page's even-row swap */
html.ab-blank .voice__fact-p { order: 2; max-width: 420px; margin: 4px 0 0; text-align: center; font-size: 15px; line-height: 1.55; color: var(--ab-soft); }
html.ab-blank .voice__fact-card { width: 100%; height: auto; aspect-ratio: 16 / 10; border-radius: 10px }
/* The screen floats in the middle of its card with the same air on all four
   sides, instead of rising from the bottom edge. */
html.ab-blank .voice__fact-card { place-items: center; }
html.ab-blank .voice__fact-screen { width: 72%; height: 72%; border-radius: 8px; }

/* How it works: the same film, framed like a Blank card. */
html.ab-blank .voice .hw .hw__frame { border-radius: 10px }
html.ab-blank .voice .hw .hw__ui { border-radius: 8px; }
html.ab-blank .hw__cap-item { font-size: 15px; font-weight: 300; color: var(--ab-soft); }

/* Pricing: three hairline cards, small and even. */
html.ab-blank .voice__pricing { padding: var(--ab-gap) 24px; }
html.ab-blank .voice__plans { max-width: 960px; margin: 40px auto 0; gap: 12px; }
html.ab-blank .voice__plan { padding: 28px 24px 24px; border-radius: 10px }
html.ab-blank .voice__plan-h { font-size: 11px; letter-spacing: .14em; text-transform: uppercase; color: var(--ab-soft); }
html.ab-blank .voice__plan--lead .voice__plan-h { color: inherit; opacity: .7; }
html.ab-blank .voice__plan-tag { font-size: 10px; letter-spacing: .1em; text-transform: uppercase; padding: 3px 8px; border-radius: 999px; }
html.ab-blank .voice__plan-amount { font-size: 30px; letter-spacing: -0.01em; }
html.ab-blank .voice__plan-per { font-size: 12px; }
html.ab-blank .voice__plan-p { font-size: 13px; line-height: 1.5; }
html.ab-blank .voice__plan-list { gap: 8px; margin: 20px 0; }
html.ab-blank .voice__plan-list li { font-size: 13px; line-height: 1.45; }
html.ab-blank .voice__plan-scope { font-size: 11px; line-height: 1.5; }

/* Close: the hero's sentence again, the same size. */
html.ab-blank .voice__close { min-height: 70vh; padding: var(--ab-gap) 24px; }
html.ab-blank .voice__close-h { font-size: clamp(26px, 3.4vw, 34px); max-width: 560px; }
/* The plan's glass fills the whole card (no panel set inside a frame), so the
   lead plan is one inverted card and the others one frosted card each. */
html.ab-blank .voice__plans .voice__plan::before { inset: 0; border-radius: inherit; }
html.ab-blank .voice__plan--lead .voice__plan-h { color: inherit; }

/* ── Home at the Blank's scale (html.ab-blank, on /) ─────────────
   The same measures as ECH0: the name set light and wide like the menu
   words, the line under it at reading size in soft ink with only the
   changing word in full ink, pill buttons at 13px, one under the other at one
   width (the second a hairline), and a foot of small capitals. The orb stays as it is. */
html.ab-blank .index__word { font-size: 34px; font-weight: 300; letter-spacing: .14em; text-indent: .14em; line-height: 1.1; }
html.ab-blank .index__text { margin-top: 0; font-size: 15px; font-weight: 300; line-height: 1.55; color: var(--ab-soft); }
html.ab-blank .index__rotor { color: var(--nix-text); }
html.ab-blank .index__cta { flex-direction: column; align-items: center; gap: 10px; margin-top: 28px; }
html.ab-blank .index__cta .btn { width: 168px; min-width: 0; min-height: 0; padding: 10px 22px; font-size: 13px; font-weight: 400; letter-spacing: .02em; border-radius: 999px; }
html.ab-blank .index__cta .btn--ghost { background: none; box-shadow: inset 0 0 0 1px var(--ab-line); }
html.ab-blank .index-foot__legal { font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--ab-soft); }

/* ── The Blank's fade under the header and above the foot ────────────────
   What scrolls fades to nothing as it passes under the header line (clear
   above its middle, full 32px under it) and again toward the bottom edge —
   the Blank's own mask, on each scroller here: #page, the index and the
   post layer. The mask is the scroller's, so it stays put while the words
   move through it; the extra room at the end lets the last line (the foot)
   rise out of the fade. */
html.ti-site { --ti-head: 54px; --ti-head-mid: 32px; --ti-foot: 54px; --ti-foot-lift: 16px; }
html.ti-site :is(main#page, main.index, .blog-layer) {
  --ti-fade: linear-gradient(to bottom, transparent 0, transparent var(--ti-head-mid), #000 calc(var(--ti-head) + 32px), #000 calc(100% - var(--ti-foot-lift) - var(--ti-foot) - 64px), transparent calc(100% - var(--ti-foot-lift) - var(--ti-foot) / 2), transparent 100%);
  -webkit-mask-image: var(--ti-fade); mask-image: var(--ti-fade);
}
/* The room at the end clears the fade completely: the mask is solid until
   134px from the bottom (16 lift + 54 foot + 64 fade), so 160px puts the
   foot's last line in full ink when the page is scrolled to its end
   (Hector, 2026-10-03). Not the index: its hero is laid out on its padding,
   and its mask fades under the header only. The open post gets the same. */
html.ti-site main#page { padding-bottom: 160px; }
html.ti-site .blog-layer { padding-bottom: 160px; }

/* ── The Blank's entrance cascade, on every page ──────────────────────────
   Each block's pieces drop in from 14px above, one after another, 70ms
   apart, the first time the block comes on screen (layer.js). Waiting
   pieces are hidden; the class comes off when the drop ends, so nothing
   keeps a transform it did not have. */
html .ti-wait { opacity: 0; }
.ti-drop { animation: ti-drop 520ms cubic-bezier(.22,1,.36,1) both; animation-delay: calc(var(--i, 0) * 70ms + 120ms); }
@keyframes ti-drop { from { opacity: 0; transform: translateY(-14px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { html .ti-wait { opacity: 1; } .ti-drop { animation: none; } }
/* The home barely scrolls and its foot sits on the bottom edge: it fades
   under the header only. */
html.ti-site main.index {
  --ti-fade: linear-gradient(to bottom, transparent 0, transparent var(--ti-head-mid), #000 calc(var(--ti-head) + 32px), #000 100%);
}

/* ── ECH0: every section a full screen ─────────────────────────────────────
   The hero, Why, each fact, the pricing and the close each stand alone on
   one screen, their content in its middle; How it works keeps its own
   scroll-pinned length. The page's 96px gap goes, so a screen is a screen. */
html.ab-blank main.voice { gap: 0; }
html.ab-blank :is(.voice__hero, .voice__why, .voice__fact, .voice__pricing, .voice__close) {
  min-height: 100vh; min-height: 100dvh; box-sizing: border-box;
  display: flex; flex-direction: column; justify-content: center; align-items: center;
}
html.ab-blank .voice__why, html.ab-blank .voice__pricing, html.ab-blank .voice__close { padding: 0 24px; }
html.ab-blank .voice__facts { gap: 0; padding: 0 24px; }
html.ab-blank .voice__fact { width: min(var(--ab-wide), 100%); padding: 48px 0; }
html.ab-blank .voice__plans { width: 100%; }

/* ── The sign-in, the Blank's way ──────────────────────────────────────────
   Login and signup keep their drop and its flight (door.js, portal.css);
   what changes is the ground and the form. The ground is the Blank's
   gradient, the same as every other page, instead of portal.css's flat
   near-black. The form is the Blank's: fields are a line of text over a
   hairline that darkens to ink on focus (no fill, no box), 16px light, with
   air between them; the button a 13px pill; the foot small capitals. */
html.ti-site body:has(.nix-door) {
  background: linear-gradient(180deg, var(--ti-bg-top) 0%, var(--ti-bg-mid) 55%, var(--ti-bg-low) 100%) fixed;
}
html.ti-site body:has(.nix-door) #wrapwrap { background: transparent; }
html.ti-site .oe_website_login_container:has(> .nix-door) {
  --door-line: color-mix(in srgb, var(--nix-text) 18%, transparent);
  --door-soft: color-mix(in srgb, var(--nix-text) 55%, transparent);
}
html.ti-site #wrapwrap .oe_website_login_container:has(> .nix-door) > form { max-width: 320px !important; }
html.ti-site #wrapwrap .oe_website_login_container:has(> .nix-door) form .input-group { margin: 0; }
html.ti-site #wrapwrap .oe_website_login_container:has(> .nix-door) form > * + * { margin-top: 18px; }
html.ti-site #wrapwrap .oe_website_login_container:has(> .nix-door) form .form-control,
html.ti-site #wrapwrap .oe_website_login_container:has(> .nix-door) form .form-control:focus {
  height: auto; padding: 8px 0 10px; border: 0; border-radius: 0; box-shadow: none;
  border-bottom: 1px solid var(--door-line); background: transparent;
  font-family: var(--font-sans); font-size: 16px; font-weight: 300; color: var(--nix-text);
  transition: border-color 250ms ease;
}
html.ti-site #wrapwrap .oe_website_login_container:has(> .nix-door) form .form-control:focus { border-bottom-color: var(--nix-text); outline: none; }
html.ti-site #wrapwrap .oe_website_login_container:has(> .nix-door) form .form-control::placeholder { color: var(--door-soft); opacity: .8; }
html.ti-site #wrapwrap .oe_website_login_container:has(> .nix-door) input:-webkit-autofill { -webkit-box-shadow: 0 0 0 1000px var(--ti-bg-mid) inset; }
html.ti-site #wrapwrap .oe_website_login_container:has(> .nix-door) form .btn-primary:not(.nix-door__send) {
  margin-top: 10px; padding: 10px 22px; border: 0; border-radius: 999px;
  font-size: 13px; font-weight: 400; letter-spacing: .02em;
}
html.ti-site #wrapwrap .nix-door__foot { font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--door-soft, currentColor); }
html.ti-site #wrapwrap .nix-door__foot a { margin-left: 8px; }

/* The sign-in's fields, written from the left: the placeholder, the text and
   the painted caret (door.js measures from the padding when the field is
   left-aligned) all start at the left edge. */
html.ti-site #wrapwrap .oe_website_login_container:has(> .nix-door) .form-control { text-align: left; }
html.ti-site .oe_website_login_container:has(> .nix-door) .nix-slot__mirror { justify-content: flex-start; }

/* They arrive in the Blank's cascade, not the resolve: each piece drops in
   from 14px above, 70ms after the one before, still after the flight. */
html.ti-site .oe_website_login_container:has(> .nix-door) > form > * {
  filter: none; transform: translateY(-14px);
  transition: opacity 520ms cubic-bezier(.22,1,.36,1) var(--in), transform 520ms cubic-bezier(.22,1,.36,1) var(--in);
}
html.ti-site .oe_website_login_container:has(> .nix-door) > form > * + * { --in: 1970ms; }
html.ti-site .oe_website_login_container:has(> .nix-door) > form > * + * + * { --in: 2040ms; }
html.ti-site .oe_website_login_container:has(> .nix-door) > form > * + * + * + * { --in: 2110ms; }
html.ti-site .oe_website_login_container:has(> .nix-door) > form > * + * + * + * + * { --in: 2180ms; }
html.ti-site .oe_website_login_container.is-soft:has(> .nix-door) > form > * { --in: 150ms; }
html.ti-site .oe_website_login_container.is-soft:has(> .nix-door) > form > * + * { --in: 220ms; }
html.ti-site .oe_website_login_container.is-soft:has(> .nix-door) > form > * + * + * { --in: 290ms; }
html.ti-site .oe_website_login_container.is-soft:has(> .nix-door) > form > * + * + * + * { --in: 360ms; }
html.ti-site .oe_website_login_container.is-soft:has(> .nix-door) > form > * + * + * + * + * { --in: 430ms; }
html.ti-site .oe_website_login_container.is-open:has(> .nix-door) > form > * { transform: none; }

/* The writing line draws itself from left to right: the hairline once, as
   its field drops in, and the ink line over it each time the field takes
   focus. Two background layers sized by two registered properties, so one
   can animate (the arrival, delayed) while the other transitions (focus,
   at once). */
@property --door-hair { syntax: "<percentage>"; inherits: false; initial-value: 0%; }
@property --door-ink { syntax: "<percentage>"; inherits: false; initial-value: 0%; }
html.ti-site #wrapwrap .oe_website_login_container:has(> .nix-door) form .form-control,
html.ti-site #wrapwrap .oe_website_login_container:has(> .nix-door) form .form-control:focus {
  border-bottom: 0;
  background:
    linear-gradient(var(--nix-text), var(--nix-text)) left bottom / var(--door-ink) 1px no-repeat,
    linear-gradient(var(--door-line), var(--door-line)) left bottom / var(--door-hair) 1px no-repeat;
  transition: --door-ink 420ms cubic-bezier(.22,1,.36,1);
}
html.ti-site #wrapwrap .oe_website_login_container:has(> .nix-door) form .form-control:focus { --door-ink: 100%; }
html.ti-site #wrapwrap .oe_website_login_container.is-open:has(> .nix-door) form .form-control {
  animation: door-line 700ms cubic-bezier(.22,1,.36,1) calc(var(--in, 0ms) + 160ms) both;
}
html.ti-site #wrapwrap .oe_website_login_container.is-instant:has(> .nix-door) form .form-control { animation: none; --door-hair: 100%; }
@keyframes door-line { from { --door-hair: 0%; } to { --door-hair: 100%; } }
@media (prefers-reduced-motion: reduce) {
  html.ti-site #wrapwrap .oe_website_login_container:has(> .nix-door) form .form-control { animation: none; --door-hair: 100%; transition: none; }
}

/* ── The account (/my), the Blank's way ───────────────────────────────────
   The rail gives way to the site's Blank menu (layer.js: the account's places
   as words, the signed-in reader at the foot with Theme, Language and
   Log out), so the panel is the whole page on the Blank's ground. The
   dashboard is one centred column: its title set like a menu word, the four
   counts as bare figures over small capitals (no card, no fill — a hover
   tint is the only sign they are doors), and the note under them as quiet
   centred text. It cascades in like every other page. */
html.ti-site body:has(#wrapwrap.nix-account) {
  background: linear-gradient(180deg, var(--ti-bg-top) 0%, var(--ti-bg-mid) 55%, var(--ti-bg-low) 100%) fixed;
}
html.ti-site #wrapwrap.nix-account,
html.ti-site #wrapwrap.nix-account > main#page { background: transparent; box-shadow: none; border-radius: 0; }
#wrapwrap.nix-account { grid-template-columns: 0 minmax(0, 1fr); }
html body #wrapwrap.nix-account main#page > .nix-dash { width: 100%; max-width: 560px; margin: 0 auto; padding: calc(54px + 38px) 24px 8vh; box-sizing: border-box; }
html.ti-site #wrapwrap.nix-account .nix-dash .nix-login__title {
  margin: 0 0 44px; font-size: 18px; font-weight: 300; line-height: 1.2; letter-spacing: .14em; text-transform: uppercase; text-align: center;
}
html.ti-site #wrapwrap.nix-account .nix-dash__stats { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 4px; max-width: none; margin: 0; }
html.ti-site #wrapwrap.nix-account .nix-dash__stat {
  align-items: center; gap: 8px; padding: 18px 6px; background: none; box-shadow: none; border-radius: 10px;
  transition: background 180ms ease;
}
html.ti-site #wrapwrap.nix-account .nix-dash__stat:hover { background: color-mix(in srgb, var(--nix-text) 5%, transparent); box-shadow: none; }
html.ti-site #wrapwrap.nix-account .nix-dash__num { font-size: 34px; font-weight: 200; letter-spacing: -0.01em; }
html.ti-site #wrapwrap.nix-account .nix-dash__label { font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: color-mix(in srgb, var(--nix-text) 55%, transparent); }
html.ti-site #wrapwrap.nix-account .nix-dash__card { max-width: none; margin-top: 56px; padding: 0; background: none; box-shadow: none; border-radius: 0; text-align: center; }
html.ti-site #wrapwrap.nix-account .nix-dash__title { margin: 0 0 10px; font-size: 20px; font-weight: 300; }
html.ti-site #wrapwrap.nix-account .nix-dash__text { max-width: 420px; margin: 0 auto; font-size: 15px; font-weight: 300; line-height: 1.6; color: color-mix(in srgb, var(--nix-text) 55%, transparent); text-wrap: balance; }
@media (max-width: 560px) {
  html.ti-site #wrapwrap.nix-account .nix-dash__stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ── The account's pages: Updates, Billing, Support, Feedback ─────────────
   All in the Blank's language, in the dashboard's 560px column: section
   names in small capitals, lists as rows with no lines between (the main line at 15px
   with its detail under it at 12px, the state or date in small capitals at
   the right, an action as a quiet word), forms as lines of text over a
   hairline, and one ink pill for the thing to do. */
.acct { --acct-soft: color-mix(in srgb, var(--nix-text) 55%, transparent); --acct-line: color-mix(in srgb, var(--nix-text) 14%, transparent); }
html.ti-site #wrapwrap.nix-account .acct .nix-login__title { margin-bottom: 40px; }
.acct-label { margin: 0 0 12px; font-size: 11px; letter-spacing: .16em; text-transform: uppercase; color: var(--acct-soft); }
.acct-block { margin-top: 48px; }
.acct-intro { max-width: 420px; margin: -16px auto 32px; text-align: center; font-size: 15px; font-weight: 300; line-height: 1.55; color: var(--acct-soft); text-wrap: balance; }

.acct-rows { list-style: none; margin: 0; padding: 0; }
.acct-rows > li, .acct-row__link { display: flex; align-items: center; gap: 20px; }
.acct-rows > li { padding: 14px 0; }
.acct-rows > li:has(> .acct-row__link) { padding: 0; }
.acct-row__link { flex: 1; padding: 14px 0; color: inherit; text-decoration: none; }
.acct-row__main { flex: 1; display: grid; gap: 3px; font-size: 15px; font-weight: 300; color: var(--nix-text); }
.acct-row__main small { font-size: 12px; color: var(--acct-soft); }
.acct-row__meta { font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--acct-soft); white-space: nowrap; }
.acct-row__meta.is-on { color: var(--nix-text); }
.acct-row__act { font-size: 13px; color: var(--nix-text); text-decoration: none; white-space: nowrap; transition: opacity 180ms ease; }
.acct-row__act:hover, .acct-row__link:hover .acct-row__main { opacity: .65; }

/* Updates: the latest release, centred, before the list of earlier ones. */
.acct-release { display: flex; flex-direction: column; align-items: center; text-align: center; }
.acct-version { margin: 0; font-size: 34px; font-weight: 200; letter-spacing: -0.01em; color: var(--nix-text); }
.acct-meta { display: flex; gap: 14px; margin: 8px 0 0; font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--acct-soft); }
.acct-meta > * + *::before { content: ""; display: inline-block; width: 3px; height: 3px; margin-right: 14px; border-radius: 50%; background: currentColor; opacity: .55; vertical-align: middle; transform: translateY(-1px); }
.acct-text { max-width: 420px; margin: 18px 0 24px; font-size: 15px; font-weight: 300; line-height: 1.55; color: var(--acct-soft); text-wrap: balance; }

/* The one thing to do: an ink pill. */
.acct-btn { display: inline-flex; align-items: center; justify-content: center; padding: 10px 22px; border: 0; border-radius: 999px; cursor: pointer;
  background: var(--nix-text); color: var(--nix-surface, var(--ti-bg-top)); font: inherit; font-size: 13px; font-weight: 400; letter-spacing: .02em; text-decoration: none;
  transition: opacity 180ms ease; }
.acct-btn:hover { opacity: .85; }

/* Forms: the Blank's fields. */
.acct-form { display: grid; gap: 22px; }
.acct-form > .acct-btn { justify-self: start; }
.acct-field { display: grid; gap: 8px; }
.acct-field > span { font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--acct-soft); }
#wrapwrap .acct-field :is(input, textarea) {
  font: inherit; font-size: 16px; font-weight: 300; color: var(--nix-text); background: transparent;
  border: 0; border-bottom: 1px solid var(--acct-line); border-radius: 0; padding: 6px 0 10px; outline: none; resize: vertical; box-shadow: none;
  transition: border-color 250ms ease;
}
#wrapwrap .acct-field :is(input, textarea):focus { border-bottom-color: var(--nix-text); }
#wrapwrap .acct-field :is(input, textarea)::placeholder { color: var(--acct-soft); opacity: .7; }
.acct-sent { margin: 0; font-size: 15px; font-weight: 300; color: var(--nix-text); }

/* Feedback's kind: three pills, the chosen one in ink. */
.acct-choices { display: flex; gap: 8px; }
.acct-choices label { cursor: pointer; }
.acct-choices input { position: absolute; opacity: 0; pointer-events: none; }
.acct-choices span { display: inline-block; padding: 7px 16px; border-radius: 999px; font-size: 13px; color: var(--acct-soft);
  background: color-mix(in srgb, var(--nix-text) 6%, transparent); transition: background 180ms ease, color 180ms ease; }
.acct-choices input:checked + span { background: var(--nix-text); color: var(--nix-surface, var(--ti-bg-top)); }
.acct-choices input:focus-visible + span { outline: 1px solid var(--acct-soft); outline-offset: 3px; }
/* The pill's words in the ground's colour; the portal colours every link in
   #wrapwrap, so this has to outrank it. */
html #wrapwrap .acct .acct-btn, html #wrapwrap .acct .acct-btn:hover { color: var(--ti-bg-mid); }
html #wrapwrap .acct .acct-choices input:checked + span { color: var(--ti-bg-mid); }
.acct-sent[hidden] { display: none; }

/* The account page's name lives in the header now (layer.js); its heading
   in the column is kept for screen readers only. */
html.ti-site #wrapwrap.nix-account .acct .nix-login__title {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.acct-intro { margin-top: 0; }

/* ── No dividing lines anywhere ────────────────────────────────────────────
   Rows and blocks are told apart by air, not rules: the pricing cards lose
   the line over their list and over Lifetime's scope note, How it works'
   stacked screens (narrow widths) the line between them. The lines under a
   field to write on stay; they are where you write, not dividers. */
html .voice__plans .voice__plan-list,
html .voice__plans .voice__plan--lead .voice__plan-list,
html .voice__plans .voice__plan-scope,
html .voice__plans .voice__plan--lead .voice__plan-scope { border-top: 0; }
html .hw:not(.is-pinned) .hw__screen + .hw__screen { border-top: 0; }
html .acct-rows > li { padding: 12px 0; }


/* ── Odoo's blog frame, out of the way ─────────────────────────────────────
   The prototype drew the blog without website_blog's own boxes; here they
   are around the list and the post (a container, a row, a column, a padded
   section), and each would add its gutter to the Blank's column. */
#wrapwrap .website_blog.nix-col :is(#o_wblog_index_content, #o_wblog_post_main, #o_wblog_post_footer) { padding: 0; margin: 0; background: none; }
#wrapwrap .website_blog.nix-col #o_wblog_index_content > .container,
#wrapwrap .website_blog.nix-col #o_wblog_index_content .row,
#wrapwrap .website_blog.nix-col #o_wblog_posts_loop_container { display: block; width: auto; max-width: none; margin: 0; padding: 0; }
#wrapwrap .website_blog.nix-col #oe_structure_blog_footer:empty { display: none; }

/* ── The account's pages, as Odoo draws them ───────────────────────────────
   An empty list says so in a quiet line; a sent form says so above the form;
   Billing's Update is a POST (Stripe's portal needs one), so its form sits in
   the row like a link and its button looks like one. */
.acct-empty { margin: 0; font-size: 14px; font-weight: 300; color: var(--acct-soft); }
.acct-sent--top { margin: -12px 0 24px; text-align: center; }
.acct-row__form { margin: 0; display: inline; }
#wrapwrap .acct .acct-row__form button.acct-row__act { padding: 0; border: 0; background: none; font: inherit; font-size: 13px; color: var(--nix-text); cursor: pointer; }
/* The cards' glass, a lighter frost (Hector, 2026-10-03): the wake now
   draws behind it, and at 6px of blur its 11px characters dissolved into a
   smudge. 2px keeps it glass — the line reads softened through it, and the
   drawing on the screen stays in front. */
html .voice__facts .voice__fact-screen,
html .voice .hw .hw__ui {
  -webkit-backdrop-filter: blur(2px) saturate(1.3); backdrop-filter: blur(2px) saturate(1.3);
  background: color-mix(in srgb, var(--nix-surface) 30%, transparent);
}

/* ── ECH0's story: Why, How, What (Hector, 2026-10-03) ─────────────────────
   The page tells it in four beats. The hero says the day; Why is one
   paragraph alone on its screen; How is a paragraph over the echo's memory
   (the Blank's 3D graph, layer.js); What is the echo's name, two paragraphs
   and the Blank's Artifacts view playing itself. Each beat is a full screen
   with its words in the Blank's reading measure. */
html.ab-blank .voice__chapter {
  min-height: 100vh; min-height: 100dvh; box-sizing: border-box; padding: 72px 24px;
  display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 28px;
}
html.ab-blank .voice__story {
  max-width: 600px; margin: 0 auto; text-align: center; text-wrap: pretty;
  font-size: clamp(18px, 2vw, 22px); font-weight: 300; line-height: 1.55; color: var(--nix-text);
}
html.ab-blank .voice__chapter .voice__story + .voice__story { margin-top: -8px; color: var(--ab-soft); }
html.ab-blank .voice__why .voice__story { max-width: 640px; }

/* How: the graph, as wide as the column for pictures and nearly as tall. */
.echo-graph { position: relative; width: min(var(--ab-wide, 720px), 100%); height: min(62vh, 620px); }
.echo-graph__canvas { display: block; width: 100%; height: 100%; cursor: grab; touch-action: pan-y; }
.echo-graph__canvas:active { cursor: grabbing; }

/* What: the Artifacts view, the Blank's list and its detail. */
.echo-arts { position: relative; width: min(480px, 100%); margin-top: 20px; min-height: 380px; }
.echo-arts__eyebrow { margin: 0 0 22px; text-align: center; font-size: 18px; font-weight: 300; letter-spacing: .14em; text-transform: uppercase; color: var(--nix-text); }
.echo-arts__rows { list-style: none; margin: 0; padding: 0; transform-origin: 50% 30%;
  transition: transform 650ms cubic-bezier(.2,.7,.2,1), filter 450ms ease, opacity 450ms ease; }
.echo-arts__rows li { display: flex; justify-content: space-between; align-items: center; gap: 20px; padding: 14px 4px; cursor: pointer;
  border-radius: 10px; transition: transform 450ms cubic-bezier(.2,.7,.2,1), background 200ms ease; }
.echo-arts__rows li:hover { background: color-mix(in srgb, var(--nix-text) 5%, transparent); }
.echo-arts__rows li.is-pressing { transform: scale(.98); background: color-mix(in srgb, var(--nix-text) 6%, transparent); }
.echo-arts__name { font-size: 16px; font-weight: 300; color: var(--nix-text); }
.echo-arts__meta { font-size: 11px; letter-spacing: .12em; text-transform: uppercase; color: var(--ab-soft); }
.echo-arts.is-open .echo-arts__rows { transform: scale(.94); filter: blur(5px); opacity: .45; }
.echo-arts__detail { position: absolute; left: 0; right: 0; top: 40px; display: grid; gap: 14px; cursor: pointer;
  opacity: 0; transform: translateY(14px) scale(.98); pointer-events: none;
  transition: opacity 400ms ease, transform 480ms cubic-bezier(.22,1,.36,1); }
.echo-arts.is-open .echo-arts__detail { opacity: 1; transform: none; pointer-events: auto; }
.echo-arts__title { margin: 0; text-align: center; font-size: 18px; font-weight: 300; letter-spacing: .14em; text-transform: uppercase; color: var(--nix-text); }
.echo-arts__preview { aspect-ratio: 16 / 10; border-radius: 16px; display: grid; place-items: center;
  background: radial-gradient(120% 90% at 20% 0%, color-mix(in srgb, var(--nix-text) 10%, transparent), transparent 60%), color-mix(in srgb, var(--nix-text) 5%, transparent); }
.echo-arts__mark { font-size: 64px; font-weight: 200; color: color-mix(in srgb, var(--nix-text) 30%, transparent); }
.echo-arts__line { display: flex; justify-content: space-between; align-items: center; padding: 4px 2px; font-size: 16px; font-weight: 300; color: var(--nix-text); }
.echo-arts__switch { position: relative; width: 34px; height: 18px; border-radius: 999px; background: color-mix(in srgb, var(--nix-text) 12%, transparent); transition: background 300ms ease; }
.echo-arts__switch i { position: absolute; top: 3px; left: 3px; width: 12px; height: 12px; border-radius: 50%; background: var(--nix-text); transition: translate 350ms cubic-bezier(.2,.7,.2,1); }
.echo-arts__detail.is-public .echo-arts__switch { background: color-mix(in srgb, var(--nix-text) 30%, transparent); }
.echo-arts__detail.is-public .echo-arts__switch i { translate: 16px 0; }
.echo-arts__addr { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding: 0 2px;
  font-size: 13px; color: var(--ab-soft); opacity: 0; transform: translateY(-4px); transition: opacity 300ms ease, transform 360ms cubic-bezier(.22,1,.36,1); }
.echo-arts__detail.is-public .echo-arts__addr { opacity: 1; transform: none; }
.echo-arts__copy { color: var(--nix-text); }
@media (prefers-reduced-motion: reduce) { .echo-arts__rows, .echo-arts__detail, .echo-arts__addr { transition: none; } }

/* How and What side by side on a wide screen (Hector, 2026-10-03): How's
   words on the left and the graph on the right; What's Artifacts view on the
   left and its words on the right. Stacked on a narrow screen, words first. */
html.ab-blank .voice__chapter-text { display: flex; flex-direction: column; gap: 20px; }
@media (min-width: 900px) {
  html.ab-blank .voice__chapter {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: center; align-content: center;
    column-gap: clamp(32px, 5vw, 80px); max-width: 1200px; margin: 0 auto; padding-inline: 48px;
  }
  html.ab-blank .voice__chapter-text .voice__story,
  html.ab-blank .voice__chapter-text .voice__h { text-align: left; margin: 0; max-width: 520px; }
  html.ab-blank .voice__chapter-text .voice__story + .voice__story { margin-top: 0; }
  html.ab-blank .voice__chapter--how .echo-graph { width: 100%; height: min(70vh, 640px); }
  html.ab-blank .voice__chapter--what .echo-arts { order: -1; width: min(460px, 100%); justify-self: center; margin-top: 0; }
}

/* What each point of the echo's graph is, beside it as it lands (layer.js). */
.echo-graph__say { position: absolute; left: 0; top: 0; pointer-events: none; white-space: nowrap;
  display: inline-flex; align-items: baseline; gap: 8px; font-size: 13px; font-weight: 300; color: var(--nix-text);
  transition: opacity 120ms linear; will-change: transform, opacity; }
.echo-graph__say b { font-weight: 400; font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--say, currentColor); }

/* The graph, touched as in the Blank: a tip naming what is under the pointer,
   and a card for a memory or a subject over the graph, which steps back
   behind it (smaller, blurred, dimmer — the Blank's depth). */
.echo-graph__tip { position: absolute; left: 0; top: 0; pointer-events: none; white-space: nowrap; font-size: 13px; font-weight: 300;
  padding: 4px 10px; border-radius: 999px; color: var(--nix-text); background: color-mix(in srgb, var(--nix-surface) 80%, transparent);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); }
.echo-graph__canvas { transform-origin: 50% 50%; transition: transform 650ms cubic-bezier(.2,.7,.2,1), filter 450ms ease, opacity 450ms ease; }
.echo-graph.is-open .echo-graph__canvas { transform: scale(.94); filter: blur(5px); opacity: .45; }
.echo-graph.is-open .echo-graph__say { opacity: 0 !important; }
.echo-graph__panel { position: absolute; left: 50%; top: 50%; width: min(380px, calc(100% - 32px)); box-sizing: border-box; padding: 26px 24px 22px;
  border-radius: 16px; background: color-mix(in srgb, var(--nix-surface) 70%, transparent); -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  opacity: 0; pointer-events: none; transform: translate(-50%, calc(-50% + 14px)) scale(.98);
  transition: opacity 400ms ease, transform 480ms cubic-bezier(.22,1,.36,1); text-align: center; }
.echo-graph.is-open .echo-graph__panel { opacity: 1; pointer-events: auto; transform: translate(-50%, -50%); }
.echo-graph__x { position: absolute; top: 10px; right: 12px; border: 0; background: none; font-size: 20px; line-height: 1; color: var(--ab-soft, currentColor); cursor: pointer; }
.echo-graph__badge { display: inline-flex; align-items: center; gap: 6px; margin: 0 0 12px; padding: 3px 10px; border-radius: 999px;
  font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--nix-text); background: color-mix(in srgb, var(--nix-text) 7%, transparent); }
.echo-graph__badge i, .echo-graph__list i { width: 6px; height: 6px; border-radius: 50%; background: var(--say, var(--nix-text)); }
.echo-graph__title { margin: 0; font-size: 20px; font-weight: 300; line-height: 1.3; color: var(--nix-text); text-wrap: balance; }
.echo-graph__text { margin: 10px 0 0; font-size: 14px; font-weight: 300; line-height: 1.5; color: var(--ab-soft, currentColor); }
.echo-graph__rows { display: grid; grid-template-columns: auto 1fr; gap: 8px 16px; margin: 20px 0 0; text-align: left; font-size: 13px; }
.echo-graph__rows dt { font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--ab-soft, currentColor); align-self: center; }
.echo-graph__rows dd { margin: 0; text-align: right; color: var(--nix-text); font-weight: 300; }
.echo-graph__rows dd[data-hub] { cursor: pointer; text-decoration: underline; text-underline-offset: 3px; text-decoration-color: color-mix(in srgb, var(--nix-text) 30%, transparent); }
.echo-graph__list { list-style: none; margin: 18px 0 0; padding: 0; text-align: left; }
.echo-graph__list li { display: grid; grid-template-columns: 6px 1fr auto; align-items: center; gap: 10px; padding: 10px 8px; border-radius: 10px; cursor: pointer;
  font-size: 14px; font-weight: 300; color: var(--nix-text); transition: background 180ms ease; }
.echo-graph__list li:hover { background: color-mix(in srgb, var(--nix-text) 6%, transparent); }
.echo-graph__list small { font-size: 10px; letter-spacing: .14em; text-transform: uppercase; color: var(--ab-soft, currentColor); }

/* The memory, as the Blank shows it (Hector, 2026-10-03): not a box but the
   Blank's memory card (.ti-memcard) standing on the receded view — kind pill,
   centred title, tag pills over a short rule, the memory, its fields — and
   the depth taking the whole chapter back, the words beside the graph too. */
.echo-graph__panel { left: 0; top: 0; right: 0; bottom: 0; width: auto; padding: 24px; display: flex; align-items: center; justify-content: center;
  background: none; -webkit-backdrop-filter: none; backdrop-filter: none; border-radius: 0; text-align: left; transform: none; }
.echo-graph.is-open .echo-graph__panel { transform: none; }
.echo-memcard { display: flex; flex-direction: column; align-items: stretch; gap: 16px; width: min(420px, 100%);
  transform: translateY(14px) scale(.98); transition: transform 480ms cubic-bezier(.22,1,.36,1); }
.echo-graph.is-open .echo-memcard { transform: none; }
.echo-memcard > .echo-memcard__kind { align-self: center; }
.echo-memcard__kind { display: inline-flex; align-items: center; gap: 6px; padding: 1px 9px 1px 7px; border-radius: 999px; font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ab-soft, currentColor); border: 1px solid color-mix(in srgb, var(--nix-text) 20%, transparent); }
.echo-memcard__kind::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--kind, var(--ab-soft, currentColor)); flex: none; }
.echo-memcard__title { margin: 0; font-size: 20px; line-height: 1.35; font-weight: 300; text-align: center; color: var(--nix-text); }
.echo-memcard__tags { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; }
.echo-memcard__tags::after { content: ""; display: block; flex-basis: 100%; height: 1px; margin: 14px auto 2px; background: linear-gradient(90deg, transparent calc(50% - 20px), color-mix(in srgb, var(--nix-text) 12%, transparent) calc(50% - 20px) calc(50% + 20px), transparent calc(50% + 20px)); }
.echo-memcard__tag { padding: 2px 9px; border-radius: 999px; font-size: 11px; letter-spacing: .04em; color: var(--ab-soft, currentColor); border: 1px solid color-mix(in srgb, var(--nix-text) 12%, transparent); }
.echo-memcard__text { margin: 0; font-size: 18px; font-weight: 300; line-height: 1.5; color: var(--nix-text); }
.echo-memcard__fields { display: flex; flex-direction: column; gap: 14px; margin: 6px 0 0; }
.echo-memcard__fields > div { display: flex; justify-content: space-between; gap: 16px; }
.echo-memcard__fields dt { font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: var(--ab-soft, currentColor); }
.echo-memcard__fields dd { margin: 0; font-size: 13px; text-align: right; color: var(--nix-text); }
.echo-memcard__fields a { color: inherit; text-decoration: underline; text-underline-offset: 3px; text-decoration-color: color-mix(in srgb, var(--nix-text) 30%, transparent); }
.echo-memcard__rows { list-style: none; margin: 0; padding: 0; }
.echo-memcard__rows li { display: flex; align-items: center; gap: 12px; padding: 12px 8px; border-radius: 10px; cursor: pointer; font-size: 15px; font-weight: 300; color: var(--nix-text); transition: background 180ms ease; }
.echo-memcard__rows li:hover { background: color-mix(in srgb, var(--nix-text) 6%, transparent); }
/* The depth: the chapter's words step back with the graph. */
.voice__chapter .voice__chapter-text { transform-origin: 60% 50%; transition: transform 650ms cubic-bezier(.2,.7,.2,1), filter 450ms ease, opacity 450ms ease; }
.voice__chapter.is-depth .voice__chapter-text { transform: scale(.94); filter: blur(5px); opacity: .45; }

/* What, person by person: the person's name changes like a view's name in
   the Blank (out blurred, in from above), their rows cascade in, and the
   opened artifact says what they asked for, in quotes, under its name. */
.echo-arts__eyebrow { transition: opacity 360ms ease, filter 360ms ease; }
.echo-arts.is-switching .echo-arts__eyebrow,
.echo-arts.is-switching .echo-arts__rows { opacity: 0; filter: blur(6px); transition: opacity 360ms ease, filter 360ms ease; }
.echo-arts.is-arriving .echo-arts__rows li { animation: ti-drop 520ms cubic-bezier(.22,1,.36,1) both; animation-delay: calc(var(--i, 0) * 70ms); }
.echo-arts.is-arriving .echo-arts__eyebrow { animation: ti-drop 520ms cubic-bezier(.22,1,.36,1) both; }
.echo-arts__ask { margin: -6px 0 2px; text-align: center; font-size: 15px; font-weight: 300; line-height: 1.45; color: var(--ab-soft, currentColor); text-wrap: balance; }
.echo-arts__ask:empty { display: none; }
@media (prefers-reduced-motion: reduce) { .echo-arts.is-arriving .echo-arts__rows li, .echo-arts.is-arriving .echo-arts__eyebrow { animation: none; } }

/* Open, the artifact is only its name and its card (Hector, 2026-10-03): no
   ask line, no switch, no address; and the person's name steps back with the
   list, in the same depth. */
.echo-arts__ask, .echo-arts__line, .echo-arts__addr { display: none; }
.echo-arts__eyebrow { transform-origin: 50% 50%; transition: transform 650ms cubic-bezier(.2,.7,.2,1), filter 450ms ease, opacity 450ms ease; }
.echo-arts.is-open .echo-arts__eyebrow { transform: scale(.94); filter: blur(5px); opacity: .45; }

/* The graph and the artifacts each in a card (Hector, 2026-10-03), filled
   with the page's own ground so it reads as the same surface lifted: no
   border, a soft shadow below and a faint light along its top edge. */
.echo-graph, .echo-arts {
  border-radius: 20px; background: var(--ti-bg-mid); box-sizing: border-box;
  box-shadow: 0 24px 60px -24px rgba(0, 0, 0, .35), 0 2px 8px rgba(0, 0, 0, .08), inset 0 1px 0 color-mix(in srgb, #fff 6%, transparent);
}
html:not([data-theme="dark"]) .echo-graph, html:not([data-theme="dark"]) .echo-arts {
  box-shadow: 0 24px 60px -28px rgba(0, 0, 0, .18), 0 2px 8px rgba(0, 0, 0, .05), inset 0 1px 0 rgba(255, 255, 255, .7);
}
.echo-graph { overflow: hidden; }
.echo-arts { padding: 28px 24px; }
.echo-arts__detail { left: 24px; right: 24px; top: 68px; }
/* No shadow and no edge light on the two cards (Hector, 2026-10-03): only
   the fill of the ground's own colour sets them off. */
.echo-graph, .echo-arts,
html:not([data-theme="dark"]) .echo-graph, html:not([data-theme="dark"]) .echo-arts { box-shadow: none; border: 0; }

/* The two cards the same size (Hector, 2026-10-03): each fills its column
   and both are as tall as each other, so How's graph and What's artifacts
   mirror each other across the page. */
html.ab-blank .echo-graph,
html.ab-blank .echo-arts,
html.ab-blank .voice__chapter--how .echo-graph,
html.ab-blank .voice__chapter--what .echo-arts {
  width: 100%; max-width: 560px; height: min(70vh, 600px); min-height: 0; margin: 0; justify-self: center;
}
html.ab-blank .echo-arts { overflow: hidden; display: flex; flex-direction: column; justify-content: center; }
@media (max-width: 899px) {
  html.ab-blank .echo-graph, html.ab-blank .echo-arts { height: min(68vh, 520px); }
}

/* "The computer is still there…" alone on its screen, the way Why is: the
   second paragraph's soft colour does not apply here. */
html.ab-blank .voice__sense .voice__story { color: var(--nix-text); margin-top: 0; }

/* "ECH0." alone on its own screen, set large (Hector, 2026-10-03): the name
   the page has been leading to, in the header's own type — light, wide
   capitals — at the size of a title. */
html.ab-blank .voice__name { min-height: 100vh; min-height: 100dvh; box-sizing: border-box; display: flex; align-items: center; justify-content: center; padding: 0 24px; }
.voice__name-word { margin: 0; font-size: clamp(64px, 11vw, 160px); font-weight: 200; line-height: 1; letter-spacing: .14em; text-indent: .14em; color: var(--nix-text); }

/* ECH0's name stands over its own wake (hero_field.js draws behind it). */
html.ab-blank .voice__name { position: relative; z-index: 1; }

/* The plans in the same card as the graph and the artifacts (Hector,
   2026-10-03): the ground's own colour, flat, no shadow, no edge, no glass
   panel. Lifetime keeps its inverted ink, the one card meant to be taken. */
.voice__plans .voice__plan:not(.voice__plan--lead) { background: var(--ti-bg-mid); box-shadow: none; border: 0; }
.voice__plans .voice__plan:not(.voice__plan--lead)::before { background: none; -webkit-backdrop-filter: none; backdrop-filter: none; box-shadow: none; }
.voice__plans .voice__plan--lead::before { box-shadow: none; }

/* Lifetime, the light card on the dark page, in the light theme's own card
   colour (the light ground's middle, #ebebe8) rather than near-white ink
   (Hector, 2026-10-03). Its words stay dark. */
html[data-theme="dark"] .voice__plans .voice__plan--lead::before { background: #ebebe8; }
html.ab-blank .voice__name-word { text-indent: .14em; }

/* The story's words, lit by the scroll (layer.js). */
.story-word { transition: opacity 180ms linear; }
.story-word { display: inline-block; transform-origin: 50% 60%; transition: opacity 180ms linear, filter 220ms linear, transform 260ms cubic-bezier(.2,.7,.2,1); }

/* Fixes (Hector, 2026-10-03).
   The page names in the header (ECH0, BLOG, the account's) in the theme's ink
   rather than white blended by difference: on the portal leg #wrapwrap is its
   own stacking context, so the blend had nothing under it and BLOG stayed
   white on the light ground. */
.nix-toplogo--word, #wrapwrap .nix-toplogo--word { mix-blend-mode: normal; }
.nix-toplogo__word { color: var(--nix-text); }
/* The menu takes the whole page back, but the blog's post layer is not part
   of the page while no post is open: it stays out of sight, or the last post
   read would show through the blur. */
html.ti-site.is-open:not(.is-post-open) body > .blog-layer { opacity: 0 !important; filter: none !important; }

/* The story's copy at 28px (Hector, 2026-10-03), the same in every
   chapter, on the hero's own scale shrunk to that ceiling: the hero is
   clamp(30px, 4.2vw, 42px), so this is two thirds of it (×28/42). */
html.ab-blank .voice__story,
html.ab-blank .voice__chapter-text .voice__story { font-size: clamp(20px, 2.8vw, 28px); line-height: 1.35; letter-spacing: -0.01em; }
html.ab-blank .voice__why .voice__story { max-width: 820px; }
@media (min-width: 900px) { html.ab-blank .voice__chapter-text .voice__story { max-width: 560px; } }

/* The artifact itself in its preview (Hector, 2026-10-03): a small, real
   screen of what was made — a quiz, a product page, an album, a recipe… —
   in the Blank's type, not a letter standing in for it. */
.echo-arts__preview { display: block; overflow: hidden; text-align: left; color: var(--nix-text); }
.mini { box-sizing: border-box; height: 100%; padding: 16px 18px; display: flex; flex-direction: column; gap: 8px; font-size: 12px; font-weight: 300; line-height: 1.35; }
.mini b { font-size: 15px; font-weight: 400; }
.mini small { font-size: 10px; letter-spacing: .1em; text-transform: uppercase; color: var(--ab-soft, currentColor); }
.mini p { margin: 0; }
.mini__btn { align-self: flex-start; margin-top: 2px; padding: 6px 12px; border-radius: 999px; font-size: 11px; background: var(--nix-text); color: var(--ti-bg-mid); }
.mini__field { padding: 6px 0; border-bottom: 1px solid color-mix(in srgb, var(--nix-text) 25%, transparent); color: var(--ab-soft, currentColor); }
.mini--quiz { justify-content: center; }
.mini--quiz b { font-size: 18px; font-weight: 300; margin-bottom: 4px; }
.mini__opt { padding: 7px 12px; border-radius: 10px; background: color-mix(in srgb, var(--nix-text) 6%, transparent); }
.mini__opt.is-on { background: color-mix(in srgb, #4f80d6 30%, transparent); }
.mini--table { gap: 0; justify-content: center; }
.mini__tr { display: grid; grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); gap: 8px; padding: 7px 2px; }
.mini__tr span:last-child { text-align: right; }
.mini__th { font-size: 10px; letter-spacing: .1em; text-transform: uppercase; color: var(--ab-soft, currentColor); }
.mini__days { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; }
.mini__days span { position: relative; padding: 4px; border-radius: 6px; font-size: 10px; text-align: center; color: var(--ab-soft, currentColor); }
.mini__days span.is-on { background: color-mix(in srgb, #4f80d6 30%, transparent); color: var(--nix-text); }
.mini__days i { display: none; }
.mini--doc { justify-content: center; }
.mini--doc b { margin-bottom: 4px; }
.mini--product { flex-direction: row; align-items: center; gap: 14px; }
.mini__img { flex: none; width: 42%; height: 100%; border-radius: 10px;
  background: radial-gradient(circle at 50% 30%, #f3e3c3 0 12%, transparent 13%), linear-gradient(180deg, transparent 40%, #9a7a52 41% 78%, transparent 79%), color-mix(in srgb, var(--nix-text) 8%, transparent); }
.mini--product > span:last-child { display: flex; flex-direction: column; gap: 6px; }
.mini--product em { font-style: normal; font-size: 20px; font-weight: 300; }
.mini--page { justify-content: center; align-items: flex-start; gap: 10px; }
.mini--page b { font-size: 24px; font-weight: 200; letter-spacing: .02em; }
.mini__li { display: grid; grid-template-columns: 12px 1fr auto; align-items: center; gap: 8px; padding: 6px 0; }
.mini__li i { width: 10px; height: 10px; border-radius: 50%; border: 1px solid color-mix(in srgb, var(--nix-text) 35%, transparent); }
.mini__li i.is-on { background: #4f80d6; border-color: #4f80d6; }
.mini--list { justify-content: center; }
.mini--board { flex-direction: row; gap: 8px; }
.mini--board > div { flex: 1; display: flex; flex-direction: column; gap: 6px; padding: 8px; border-radius: 10px; background: color-mix(in srgb, var(--nix-text) 5%, transparent); }
.mini--board > div span { padding: 6px 8px; border-radius: 8px; background: color-mix(in srgb, var(--nix-text) 9%, transparent); }
.mini--cards { align-items: center; justify-content: center; }
.mini__card { width: 72%; padding: 18px; border-radius: 14px; text-align: center; display: flex; flex-direction: column; gap: 8px; background: color-mix(in srgb, var(--nix-text) 7%, transparent); }
.mini__card b { font-size: 18px; font-weight: 300; }
.mini--timer { align-items: center; justify-content: center; gap: 4px; }
.mini--timer b { font-size: 64px; font-weight: 200; line-height: 1; }
.mini--album { gap: 8px; }
.mini__grid { flex: 1; display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.mini__grid span { border-radius: 8px; background: linear-gradient(160deg, hsl(calc(200 + var(--k) * 22) 35% 62%), hsl(calc(220 + var(--k) * 22) 30% 38%)); }
.mini--recipe { gap: 5px; justify-content: center; }
.mini--recipe b { font-size: 17px; }
.mini--recipe p::before { content: "·  "; color: var(--ab-soft, currentColor); }
/* The preview is a screen: solid, so the list behind it does not show through. */
.echo-arts__preview { background: color-mix(in srgb, var(--nix-text) 6%, var(--ti-bg-mid)); }
html .echo-arts .echo-arts__preview { display: block; place-items: initial; }
.mini { width: 100%; }
.mini__tr { grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); }
.mini__tr span:first-child { grid-column: span 1; }
.mini--cal, .mini--album { justify-content: center; }

/* ── Memory and Artifacts, explained (layer.js) ────────────────────────────
   The card and its button as one figure; the button a quiet pill under the
   card. Pressed, the page steps back exactly as for the menu and a blog post
   (scale .94, blur 10px, .20) and the explanation stands in front of it. */
.echo-figure { display: flex; flex-direction: column; align-items: center; gap: 18px; width: 100%; max-width: 560px; justify-self: center; }
@media (min-width: 900px) { html.ab-blank .voice__chapter--what .echo-figure { order: -1; } }
.echo-explain { padding: 9px 20px; border: 0; border-radius: 999px; cursor: pointer; font: inherit; font-size: 13px; font-weight: 400; letter-spacing: .02em;
  color: var(--nix-text); background: color-mix(in srgb, var(--nix-text) 8%, transparent); transition: background 180ms ease; }
.echo-explain:hover { background: color-mix(in srgb, var(--nix-text) 14%, transparent); }
html.ti-site.is-explain-open body > :not(.ti-chrome):not(.explain-layer) { transform: scale(.94); filter: blur(10px); opacity: .20; pointer-events: none; }
.explain-layer { position: fixed; inset: 0; z-index: 900; overflow-y: auto; display: flex; justify-content: center; align-items: flex-start;
  padding: 96px 24px 12vh; box-sizing: border-box; opacity: 0; pointer-events: none; transition: opacity 400ms ease; }
html.is-explain-open .explain-layer { opacity: 1; pointer-events: auto; }
.explain-layer__card { width: min(560px, 100%); cursor: auto; transform: translateY(14px) scale(.98); transition: transform 480ms cubic-bezier(.22,1,.36,1); }
html.is-explain-open .explain-layer__card { transform: none; }
.explain-layer__eyebrow { margin: 0; text-align: center; font-size: 18px; font-weight: 300; letter-spacing: .14em; text-transform: uppercase; color: var(--nix-text); }
.explain-layer__lede { margin: 14px 0 40px; text-align: center; font-size: clamp(22px, 2.6vw, 30px); font-weight: 300; line-height: 1.25; color: var(--nix-text); }
.explain-layer__item { margin: 0 0 26px; }
.explain-layer__item h3 { margin: 0 0 6px; font-size: 11px; font-weight: 400; letter-spacing: .14em; text-transform: uppercase; color: var(--ab-soft, currentColor); }
.explain-layer__item p { margin: 0; font-size: 17px; font-weight: 300; line-height: 1.55; color: var(--nix-text); }
html.ti-site.is-open:not(.is-explain-open) body > .explain-layer { opacity: 0 !important; filter: none !important; }   /* not shown through the menu while closed */

/* ECH0's sections never shrink (Hector, 2026-10-03). The page is a flex
   column of fixed height that scrolls, so its sections were squeezed down to
   their one-screen minimum while their content stayed taller: on a phone the
   stacked plans and the How / What chapters spilled over their neighbours.
   A section is now at least a screen and as tall as what it holds. */
html.ab-blank main.voice > * { flex-shrink: 0; }

/* Blog list on a narrow screen (Hector, 2026-10-03): a long title stays on
   one line and ends in an ellipsis, so it never runs into its date. */
#wrapwrap .nix-row .nix-row__main { flex: 1; min-width: 0; }
#wrapwrap .nix-row .nix-row__title { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
