/* ------------------------------------------------------------ faces
   the two faces travel with the page instead of being looked for on the
   machine. named in a stack they were only ever found where they were
   already installed, which is the author's machine and almost nobody
   else's; everyone else read the site in the system grotesque.

   font-display: block, not swap. swap paints a fallback and re-paints
   when the real face lands, so every line on the page visibly re-wraps.
   these are small files off the same origin; the wait is a moment.

   NOTE: this block is the fourth thing duplicated across the three
   pages, after :root, the masthead and the footer. it belongs in one
   stylesheet the day those are pulled out.                          */

/* one file for both cuts and everything between. the readings, the
   badges and the track chips are set at 700, and the weight axis gives
   them a real bold instead of an outline the browser smears to fake one.

   the RANGE is not decoration: this file own default instance is 200,
   extra light. declare a single weight and the page goes pale.        */

.p-index {
    /* palette lifted from the ashfall panel itself, sat on true black.
       the page is #000: there is no "page colour", only the ink on it
       and the one surface that lifts off it.                          */
    --bg:      #000000;
    --bg-lift: #0d0d0d;   /* the only raised surface: fig. 1 */
    --ash-0:   #e8e8e8;   /* primary text   */
    --ash-1:   #b6b6b6;   /* secondary      */
    --ash-2:   #7e7e78;   /* tertiary       */
    --ash-3:   #59594f;   /* quiet          */
    --rule:    #1c1c1c;   /* hairlines      */
    --rule-lit:#303032;
    /* ashfall's blue. it belongs to the PANEL, not to this site —
       so it is never what a link does when you point at it. it is
       reserved for identifying the product itself.               */
    --accent:  #9db4c7;

    /* what the site does on hover instead: it brightens to the same
       white the page already uses for primary text. not #fff — the
       page has no pure white anywhere, and shouldn't start now.   */
    --lit:     var(--ash-0);

    /* whatever the machine would have used on its own. kept as its own
       pair so the "System" button in the dev panel has something true
       to reset to now that the site declares faces of its own.       */
    --sys-sans: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

    /* Ronzino несёт всё. Остальное падает в системный стек, никогда в
       голый generic.

       both were chosen against this site at its own sizes rather than off
       a specimen. Ronzino is an anonymous Arial replacement, so its set
       width landed within a percent of the face it replaced and the prose
       did not have to be re-fitted; what it did cost is cap height, 68
       against 73, so display sizes sit lower than they used to.       */
    --sans: "Ronzino", var(--sys-sans);

    /* шапка. числа с and2es.com, кегль пересчитан под Ronzino.
       ручки живьём — masthead.html.                             */
    --mast-size:   11.5px;
    --mast-plate:  14px;
    --mast-padx:   3px;
    --mast-gap:    3px;
    --mast-radius: 2px;
    --mast-slot:   103px;
    --mast-track:  0.012em;
    --mast-inset:  10px;
    --mast-top:    9px;

    /* the mono alternates: the second a, the second g, the alternate 6
       and 9, the lifted asterisk and the alternate l. safe on :root --
       Ronzino carries no cv features at all, so these five can only
       ever reach the mono.                                          */

    /* ---- page geometry --------------------------------------------
       two absolute x-coordinates, measured from the left edge of the
       viewport and nothing else:

         x1 = --page-pad                             (labels, wordmark)
         x2 = --page-pad + --label-col + --label-gap (everything else)

       there is no centred container, so resizing or zooming the window
       does not drag the columns inward. the slack collects on the right,
       where nothing is anchored, and the type keeps its position.      */
    /* Мишень больше не гасится. Грунт в самом файле — 233, то есть
       #e9e9e9, поэтому 0.996 сажает его ровно на #e8e8e8. Гашение
       до 0.35 снято 21 августа: баннер снова светлый.            */
    --backdrop-dim: 0.996;
    --page-pad:    28px;

    /* переход между страницами */
    --slide:       620ms;   /* вся длительность                     */
    --dim:          0.25;   /* до какой яркости гаснет старая        */
    --lift:          18%;   /* насколько старая уходит вверх         */
    --lift-time:     0.6;   /* на какой части хода она трогается     */
    --scale:        0.94;   /* и во сколько ужимается, уходя вглубь   */

    /* ---- передний блок. все числа, из которых он сложен, лежат здесь
       и больше нигде; tuner.html водит именно их.                   */
    /* кнопка стоит ровно на середине окна, и это выражение, а не
       подобранное число: 41.7 — высота шапки, 20 — верхнее поле
       регистра, дальше строка подписи, её собственный отступ и
       половина её высоты. Строка подписи взята выражением, а не
       числом: при 1.65 её коробка это кегль на 1.65, поэтому кнопка
       остаётся на середине при любом кегле подписи — иначе ползунок
       в tuner уводил бы её вниз. Держится на любой высоте окна. На
       той же середине стоит next, поэтому они идут одной строкой. */
    --block-top:   calc(50vh - 41.7px - 20px - var(--no-size) * 1.65
                        - var(--view-y) - var(--view-h) / 2);
    --block-left:    0px;
    --name-x:        0px;
    --view-x:        0px;
    --view-y:        5px;

    --no-size:      12px;
    --name-size:    23px;
    --view-w:      140px;
    --view-h:       15px;
    --view-size:    12px;

    --no-track:  0.002em;
    --name-track: 0.05em;  /* gutter left and right              */
    --label-col:  108px;  /* the mono "01 / ashfall" column     */
    --label-gap:   32px;
    --body-max:   860px;  /* how wide content is allowed to run */

    /* первый экран и его ход. стенд blur.html водил их.

       22 августа --field снят в НОЛЬ. Под первым экраном было полэкрана
       чёрного, и весь этот ход покупал 2.93px размытия в упоре. Хода
       теперь нет, полоса прокрутки стоит на месте: её рисует site.css,
       а не содержимое.

       23 АВГУСТА РАЗМЫТИЕ ПО ПРОКРУТКЕ СНЯТО СОВСЕМ, вместе с --run.
       Оно считалось мёртвым, потому что листать index нечего — но на
       переходе документ на полсекунды подпирается высотой уходящего
       листа, чтобы не схлопнулась полоса. В эти полсекунды index
       ЛИСТАЕТСЯ, и размытие оживало: замер — прокрутка на 400 при
       --run 300vh давала blur(3.49px) поверх первого экрана, и оно
       висело до конца хода.

       23 АВГУСТА СНЯТ И --blur-max. Он держался последним потребителем —
       из него считалось размытие листа под открытым окном; окно с того
       же дня не размывает, а затемняет, и считать стало нечего.    */
    --field:         0vh;

    --in:  220ms;  /* arrival */
    --out:  90ms;  /* departure is faster than arrival */
}

.p-index * { box-sizing: border-box; margin: 0; padding: 0; }

/* -------------------------------------------- первый экран и его ход
   передняя страница по-прежнему одноэкранная по содержанию: шапка
   вверху, регистр между ней и подвалом. но под ней теперь есть ход
   ровно в один экран, и он ничего не листает — он только уводит
   первый экран в размытие. пустота под ним не дырка: это место, куда
   встанут следующие блоки.

   механика снята с becaneparis.com: первый экран приколот, следующий
   блок наезжает на него снизу. у них он за тот же ход затемняется
   (--overlay 0→1, замер: 88px → 0.107, 439 → 0.533, 790 → 0.959, то
   есть ровно scrollY/100vh), здесь вместо затемнения размытие.      */
/* flex-shrink: 0 у обоих — это не украшение, а починка.
   Лист во время перехода получает position: fixed; inset: 0, то есть
   ОПРЕДЕЛЁННУЮ высоту в один экран. Колонка внутри тут же сжимает свои
   части, чтобы уложиться: 100vh + 44vh не влезают в 100vh, и оба едут
   в 0.694 от себя. Замер: баннер 824 → 572, поле 363 → 252, и эти 252
   пикселя чёрного вылезали на экран ровно на время перехода, 490 мс.
   Без сжатия поле остаётся за нижним краем и обрезается, как и должно. */
.p-index .banner {
    position: sticky;
    top: 0;
    z-index: 1;
    height: 100vh;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
}

/* Поимённые размытия под открытым окном сняты 23 августа вместе с самим
   размытием: лист теперь затемняется одним слоем, и обходить окно
   селекторами больше не нужно. См. site.css.                       */

/* чёрное поле. позиционировано нарочно: непозиционированный фон
   рисуется ПОД приколотым экраном, а он должен наезжать сверху.   */
.p-index .void {
    position: relative;
    z-index: 2;
    height: var(--field);
    flex-shrink: 0;
    background: var(--bg);
}

.p-index {
    background: var(--bg);
    color: var(--ash-1);
    font-family: var(--sans);
    font-size: 15px;
    line-height: 1.65;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
    display: flex;
    flex-direction: column;
}

/* a negative, not a colour. the accent identifies the product; it has
   no business marking selected text. swapping the page's own two
   values follows any theme for free.                              */
.p-index ::selection { background: var(--ash-0); color: var(--bg); }

.p-index a {
    color: var(--ash-0);
    text-decoration: none;
    border-bottom: 1px solid var(--rule-lit);
    transition: color var(--out), border-color var(--out);
}
.p-index strong { color: var(--ash-0); font-weight: 500; }

/* ---------------------------------------------------------- layout
   one column of measure, offset left. asymmetry is the grid,
   not a decoration.

   the page is not centred and has no outer limit — it is pinned to
   the left gutter. measure is held by --body-max and the ch limits
   on prose, never by the width of a wrapper.                       */

.p-index .page {
    position: relative;
    z-index: 1;           /* над подложкой */
    flex: 1;
    display: flex;
    flex-direction: column;
    padding: 0 var(--page-pad);
}

/* the footer mirrors the masthead: one thing on the left gutter, one
   on the right. the page is then bracketed by the same gesture top
   and bottom, instead of the top being split and the bottom drifting
   into the middle of the width.                                     */
.p-index footer {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--page-pad);
    flex-wrap: wrap;
}

/* ---------------------------------------------------------- register
   the whole of the front page, held between the masthead and the
   footer. it takes all the slack between them and now hands it to one
   word — so nothing drifts, and nothing scrolls, because there is
   nowhere to scroll to.                                              */

.p-index .register {
    flex: 1;
    min-height: 0;                 /* let the render shrink here instead
                                      of pushing the page past one screen */
    display: flex;
    flex-direction: column;
    padding: 20px 0;               /* equal air, top and bottom */
}

/* one entry: the name at display size on the left, the particulars
   small on the right, the whole block clickable.

   it runs the full content width, edge to edge — and it is still not
   a stripe, because the type inside does not answer to the block, it
   answers to the page. the side inset IS the page margin, so the name
   falls on the same left line as the wordmark and the footer, and the
   particulars fall on the same right line as the nav above and the
   nav below. every piece of reading matter on the page then stands on
   one of two spines, --page-pad in from each edge; the border — the
   one mark that is not type — is the only thing let past them,
   hanging on the content edge as a full-width bracket. a letter holds
   the line; a mark hangs.                                           */
.p-index .entry {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: end;
    gap: 20px 40px;
    border: 1px solid var(--rule);
    /* the border sits on the content edge; the inset is the page
       margin less the border's own hairline, so it is the TEXT that
       lands exactly on the spine, not the frame. the left inset, the
       right inset, and the nav's distance from the edge are then one
       and the same value.                                          */
    margin: 0 calc(var(--page-pad) * -1);
    padding: 30px calc(var(--page-pad) - 1px);
    /* a drop. enough that the corner is not a right angle, not enough
       that anyone would call it rounded — the block stops looking cut
       out of the page with a knife and starts looking made.        */
    border-radius: 4px;
    transition: background var(--out), border-color var(--out);
}
/* stacked with a gap, not welded by a shared rule: black between the
   blocks is what will make several of them read as a catalogue.    */
.p-index .entry + .entry { margin-top: 8px; }

.p-index .entry-name {
    /* a specimen size: the name is the argument, so it is set to claim
       the field, not to label it. 104 is the largest fixed step that
       still clears the particulars at the tightest width the row keeps
       before it stacks (the 720px breakpoint) — so the word never
       collides with the meta on the way down.

       fixed on purpose. a vw middle term would tie the name to the
       window and make it breathe on every resize — the one motion the
       register must not have. it scales with the whole page under zoom,
       like all type, but it does not ride the viewport on its own. one
       size for every entry: big AND uniform, so a future list is a
       column of names, not a row of mismatched heroes.               */
    font-size: 104px;
    line-height: 0.86;
    letter-spacing: -0.032em;   /* display size: pulled in harder */
    /* optical margin alignment. the glyph carries a left side-bearing
       that scales with the size; at 104px it is finally visible, so
       the box sits on the spine but the LETTER looks inset. pull the
       name back by roughly that bearing so the visible edge, not the
       box edge, lands on x1 with the wordmark and the footer. the
       value is face-specific — tune it against the rendered font.    */
    margin-left: -0.03em;
    color: var(--ash-0);
    transition: color var(--out);
}

.p-index .entry-meta {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    font-family: var(--sans);
    font-size: 12px;
    line-height: 1.7;
    color: var(--ash-2);
    letter-spacing: 0.02em;
    transition: color var(--out);
}
.p-index .entry-no { color: var(--ash-3); transition: color var(--out); }

/* the transition into the product is the product's colour arriving.
   this is the one place the blue belongs on this site: it is not a
   hover style, it is ashfall identifying itself.                   */
/* ------------------------------------------------------- the way in
   the banner is gone: .viz was the frame, poster.jpg its ground, and
   the two came out together. both files stay in the folder.

   what is left is the only thing on the page you can press, and it is
   now two lines rather than one word: the number over the name. no box,
   no frame, no ground under it.

   TWO LINES AT ONE SIZE, which is the whole of the borrowed idea. both
   are 13px, the size the wordmark and the nav already run at, so the
   page still has no step between its parts -- xk.studio carries a
   twelve-pixel cap across twenty-six elements and never opens a second
   one. the hierarchy is carried by colour instead: --ash-2 is the grey
   the nav sits at when it is not your page, and the name keeps the
   #ffffff asked for when it was still the single word. that white is
   the only pure white on the site.

   RIGHT, on the spine the nav above and the nav below already hold --
   no padding on the sides, so it is the letters that land on it and not
   a box. centred in the register's slack by a pair of auto margins;
   before it stood on the floor, centred across.                       */
/* the link is the NAME only. the number is a label beside it, not part
   of the target, so the block is a plain box and the <a> is one line
   inside it.                                                          */
.p-index .way-in {
    /* Ровно то же правило, что на untitled. Блок — якорь перехода, он
       обязан стоять на обеих страницах в одних координатах, а для этого
       обе должны позиционировать его ОДИНАКОВО. Раньше index держал его
       в потоке, untitled фиксированно, и они расходились на 23 px.   */
    position: fixed;
    top: calc(41.7px + 20px + var(--block-top));
    left: calc(var(--page-pad) + var(--block-left));
    z-index: 700;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    font-family: var(--sans);
}

.p-index .way-words {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    /* то же имя, что у блока на untitled */
}

.p-index .way-no {
    font-size: var(--no-size);
    letter-spacing: var(--no-track);
    color: #ffffff;
}
.p-index .way-name {
    font-size: var(--name-size);
    line-height: 0.9;
    letter-spacing: var(--name-track);
    margin-left: var(--name-x);
    color: #ffffff;
}

/* кнопка. белое поле, чёрное слово, слово центрируется коробкой, а не
   отступами — поэтому при любых размерах оно остаётся посередине.   */
.p-index .view {
    display: flex;
    align-items: center;
    justify-content: center;
    width: var(--view-w);
    height: var(--view-h);
    margin-top: var(--view-y);
    margin-left: var(--view-x);
    background: var(--ash-0);
    color: var(--bg);
    border: 0;
    border-radius: 0.154em;
    font-size: var(--view-size);
    letter-spacing: 0.01em;
}
/* Правила переключателя `next` сняты 24 августа вместе с ним самим.
   Стоял приколоченным к правому краю на --page-pad, по высоте на
   середине окна через 0.825em, чёрным по мишени. Слепок файла —
   archive/page-index-2026-08-24-pre-next-cut.css.                  */
/* подложка. лежит под всем и не листается: приколота к окну и обрезана
   по covering, поэтому при любой форме окна кадр остаётся заполненным. */
.p-index .backdrop {
    position: fixed;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* мишень светит средним 233, и белый текст на ней давал контраст
       1.22 — не читалось вовсе. 0.35 даёт 81 и контраст 7.9, при этом
       разметка остаётся отчётливой. подложка временная, число тоже.  */
    filter: brightness(var(--backdrop-dim, 0.35));
    z-index: 0;
}

/* the reduced-motion rule is gone with the loop it was written for:
   nothing on this page moves now, so there is nothing to ask it to
   stop. it comes back with the video, not before.                    */

/* ---------------------------------------------------------- masthead

   Плашки, снятые с and2es.com 21 августа, набранные Ronzino.
   Прежний вариант — одна чёрная плита во всю строку с `ashen one` и
   `docs` на ней, Commit Mono 13 — лежит в archive/index-2026-07-29-b.html
   и в истории этого файла.

   ЧИСЛА их, кроме кегля. У них 11 на Arial; Ronzino ниже по прописной
   (68 против 72 на сотне), поэтому 11.5 — это тот же оптический размер,
   а не другой. Мерено на стенде masthead.html, там же ручки.

   Три группы в одной строке: левая по краю, средняя ровно по центру
   окна, правая по правому краю. Пункты средней стоят в слоте одной
   ширины, поэтому `sympathy` и `license` одинаковы — их приём.

   Плашка чёрная с белым текстом, как на белом листе: на index виден не
   чёрный грунт, а гашеная мишень, и чёрное по ней читается.          */

.p-index .masthead {
    /* приколота к окну, а не к листу: она вынесена из баннера, чтобы не
       уходить в размытие вместе с ним.                               */
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 800;
    display: flex;
    align-items: center;
    gap: var(--mast-gap);
    padding: var(--mast-top) var(--mast-inset);
    background: transparent;
}

/* средняя группа держится центра ОКНА, а не остатка строки: иначе она
   ездит от длины левой и правой.                                     */
.p-index .mast-mid {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    gap: var(--mast-gap);
}
.p-index .mast-left  { display: flex; gap: var(--mast-gap); }
.p-index .mast-right { display: flex; gap: var(--mast-gap); margin-left: auto; }

/* сама плашка. высоту держит коробка, а не интерлиньяж, поэтому 14
   остаётся 14 при любом кегле и любом шрифте.                        */
.p-index .pill {
    display: inline-flex;
    align-items: center;
    height: var(--mast-plate);
    padding: 0 var(--mast-padx);
    border: 0;
    border-radius: var(--mast-radius);
    background: #000000;
    color: #ffffff;
    font-family: var(--sans);
    font-size: var(--mast-size);
    letter-spacing: var(--mast-track);
    line-height: 1;
    white-space: nowrap;
}
/* один слот на все пункты меню */
.p-index .mast-mid .pill { width: var(--mast-slot); }

/* ---------------------------------------------------------- footer */

.p-index footer {
    /* приколот к низу окна и не двигается: он вне первого экрана,
       поэтому остаётся резким, когда тот уходит в размытие. поля по
       бокам теперь его собственные — раньше их давал .page.        */
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 3;
    /* sits close to the floor. the gap under it matches the gap over
       the wordmark, so the page is held between two equal margins    */
    padding: 22px var(--page-pad) 18px;
    font-family: var(--sans);
    font-size: 11px;
    /* чёрный, а не пепел: подвал лежит на мишени, а не на чёрном
       грунте, и светлая краска по ней не читается.              */
    color: #000000;
}

/* ---------------------------------------------------------- narrow */

@media (max-width: 720px) {
    .p-index { --page-pad: 20px; }
    /* the second anchor folds onto the first — one coordinate, still
       absolute, still measured from the left edge.                  */
    .p-index footer { gap: calc(var(--page-pad) / 4) var(--page-pad); }
    .p-index .register { padding: 28px 0; }
    /* still full-bleed, still two spines — the inset just tracks the
       narrower page margin, so the rule holds at every width.       */
    .p-index .entry {
        grid-template-columns: minmax(0, 1fr);
        align-items: start;
        padding: 22px calc(var(--page-pad) - 1px);
    }
    .p-index .entry-meta { align-items: flex-start; }
}

/* ------------------------------------------------- переход между страниц
   настоящая навигация: адрес меняется, F5 и «назад» работают, каждая
   страница грузит только своё. анимацию играет сам браузер — скрипт не
   нужен. в firefox её не будет, там просто обычный переход.

   старая страница СТОИТ, а не уезжает: без этого браузер разводит их
   крест-накрест и получается подмена, а не налистывание. новая выходит
   снизу и накрывает.                                                 */

/* полоса носит одно имя на всех страницах, поэтому браузер понимает,
   что это один и тот же объект, и оставляет её на месте.            */

/* НОВАЯ идёт снизу. кривая снята с becaneparis: quintEaseOut,
   .22 1 .36 1. первая контрольная точка уже стоит на единице, поэтому
   разгона нет вовсе — страница трогается на полной скорости и всю
   дорогу только гасится. это и есть их подхват: не «поехала», а «уже
   едет» с первого кадра.                                            */

/* СТАРАЯ делает два движения разом, и они не совпадают по времени.
   темнеет она с самого начала и ровно, а вверх трогается только на
   последней части хода — когда новая её уже почти закрыла.

   КРИВАЯ подъёма зеркальна кривой входа, тоже с becaneparis:
   quintEaseIn, .64 0 .78 0. вторая контрольная точка на нуле, значит
   торможения в конце нет — старая трогается с места и разгоняется до
   самого конца, уходя из кадра на полном ходу. пара out/in, вход
   гасится, выход разгоняется, — это их приём, а не наш.             */

/* подъём и ужатие — одно движение и один момент: старая уходит вверх и
   вглубь разом, когда её подхватывает приходящая.                    */
