/* The shared theme (Material 3): the tokens, the topbar, the tabs, the status
   dot, the footer */
:root{
  /* a deep background plus contrasting layers: richer rather than washed out */
  --bg:#0e0e10;          /* surface */
  /* THE PLATE OF THE NAVIGATION lies BELOW a card */
  --panel-lo:#151618;    /* surface-nav: the pills and the pager */
  --panel:#1c1d1f;       /* surface-container: the cards, the table */
  --panel-hi:#2a2c2f;    /* surface-container-high: the highlighted blocks */
  --panel-top:#383b3f;   /* surface-container-highest: the selected segment of a capsule lying on
   --panel-hi (a card, a navigation sheet) */
  --hover:rgba(255,255,255,.05);
  --line:rgba(255,255,255,.08);
  --line2:rgba(255,255,255,.06);
  --text:#eceded; --text2:#bdc1c6; --dim:#9aa0a6; --faint:#75777a;
  --up:#2ecc71; --down:#e0544c; --warn:#ff9f0a; --accent:#5aa2ff;
  /* ВСЕ УПРАВЛЯЮЩИЕ ЭЛЕМЕНТЫ ОДНОЙ ВЫСОТЫ: капсула, поле, мелкая кнопка,
     кнопка копии */
  --ctl:28px;
  /* БОКОВОЙ ОТСТУП СОДЕРЖИМОГО - ОДИН НА ВСЕХ */
  --pad:24px;
  --head:#fff;           /* the section headings: a tone brighter than the text */
  /* the shadows: in the light a hard black shadow looks dirty - hence tokens */
  --shadow-pop:0 14px 36px rgba(0,0,0,.5);      /* the menus, the popovers */
  /* the lift of a small control above a plate (the pill of a switcher) */
  --lift:0 0 5px rgba(0,0,0,.12);
  --mono:"Ubuntu Mono",ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  --ui:Ubuntu,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
  /* ── THE READING COLUMN OF THE FEEDS (the owner, 24.08.2026) ─────────────
     Tape and News set an entry in the same two voices - 700/18 over 400/16 -
     and a feed is read by the LENGTH OF ITS LINE, so the measure belongs to
     both feeds or to neither. It belonged to each separately: Tape at 800 after
     the count was made on the stand, News at 760 picked beside it while its own
     comment promised "the same reading column". One decision written twice
     drifts, and this one had.
     THE NUMBER IS A COUNT OF CHARACTERS, not of pixels: 800 gives just under a
     hundred to the line of the body, against 89 at 720, 82 at 660 and about 105
     at the 900 that made the feed heavy. It is a CEILING rather than a starting
     point - a hundred characters already stands where the fatigue begins - so
     whoever moves it next has room downwards and none upwards.
     Geometry, not colour: no theme redefines it. */
  --read-col:800px;
}
/* ── the light theme (html.light, the toggle lives in the topbar): the background
     is white and the plates are a warm milky tone half a step deeper; the
     semantics and the ramp keep the same spirit but darker - the contrast of a light
     surface ── */
html{color-scheme:dark}
html.light{
  color-scheme:light;
  /* ── THE SURFACE IS WHITE, AND THE LADDER MOVED UP A STEP (the owner,
     16.08.2026: "both should be white") ─────────────────────────────────────
     The background was a warm milky #f7f6f3 while the landing was pure white,
     and crossing from the site into the app read as leaving one product for
     another. The whole ladder simply shifted: what was the background is now
     the first panel, so every surface keeps a neighbour it was designed
     against and only the ground under them turned white. */
  --bg:#ffffff;          /* surface: white, the same white as the site */
  /* on paper there is nothing to quiet: the ground is white and the card
     almost white, so a step between them is invisible and the pill simply
     dissolved */
  --panel-lo:#f7f6f3;
  --panel:#f7f6f3;       /* the cards: the warm milky tone this ladder began on */
  --panel-hi:#efeeeb;    /* the highlighted blocks: deeper */
  --panel-top:#e3e1dc;   /* one more step, of the same size as panel -> panel-hi */
  --hover:rgba(0,0,0,.06);
  --line:rgba(0,0,0,.13);
  --line2:rgba(0,0,0,.08);
  /* the greys are darker than an "inversion" of the dark ones */
  --text:#101012; --text2:#29292d; --dim:#3b3b41; --faint:#5b5a54;
  --up:#17924e; --down:#bd3f36; --warn:#a86e00; --accent:#2f6bd8;
  /* the same four tones on paper: darker, by the rule the heat ramp already
     follows */
  --head:#050506;
  --shadow-pop:0 14px 36px rgba(0,0,0,.16);
  --lift:0 0 4px rgba(0,0,0,.05);
}
/* A change of theme is instant. The class hangs for exactly the time of the
   swap of the palette (nav.js removes it after two frames) */
html.no-anim, html.no-anim *, html.no-anim *::before, html.no-anim *::after{
  transition:none !important; animation:none !important}
/* the roles that need a tone darker than the shared --dim in the light */
html.light h1.mark{color:var(--head)}
html.light .b-logo{color:var(--head)}
html.light .tagline{color:var(--head)}
html.light .sec-note{color:var(--text2)}
*{box-sizing:border-box}
/* a stable scrollbar gutter: pages of different lengths do not shift the content
   sideways */
html{-webkit-font-smoothing:antialiased;scrollbar-gutter:stable}
/* A column flex over the full height of the window plus main{flex:1} below */
body{position:relative;   /* the anchor of the absolutely placed global menu */
     margin:0;color:var(--text);font:14px/1.5 var(--ui);background:var(--bg);
     min-height:100vh;display:flex;flex-direction:column}
body > main{flex:1 0 auto}
body > footer{flex:none}
/* IMPORTANT: the header, the tabs, main and the footer all carry `margin:0
   auto` (the centring at max-width:1180px), and an auto margin on the cross
   axis DISABLES the stretch */
body > .topbar,body > .tabs-wrap,body > main,
body > footer{width:100%}
::selection{background:rgba(138,180,248,.30)}
/* the focus: the blue UA ring is out of tune - a mouse click leaves no ring while
   keyboard navigation gets a quiet one of its own */
:focus{outline:none}
:focus-visible{outline:2px solid var(--faint);outline-offset:2px}
.up{color:var(--up)} .down{color:var(--down)} .zero{color:var(--dim)}

/* ── [hidden] IS STRONGER THAN ANY LAYOUT ──────────────────────────────────
   The browser hides an element with the attribute by a rule of the lowest
   weight (html{display:none}), so ANY selector of ours with a display beats it -
   and the element stays on screen while the code is sure it is gone. The
   project met this four times and patched it four times point by point
   (.data-menu[hidden], .nav-sheet[hidden], #awa_grp[hidden], a.sum-copy[hidden]);
   the fifth case (the empty plates of the Macro section, which
   `.card:has(.nquiet) > *:has(.nquiet)` was stretching into a flex column) is
   where the patches stop and the law begins. */
[hidden]{display:none !important}

/* ── THE GLOBAL MENU OF THE PORTAL (built by nav.js, one place for every page) ──
     The project stopped being one site about ETH: ETH is a SECTION, MCP is another,
     BTC will be the third. Sections live on the vertical axis, the pages of a section
     on the horizontal one - two axes, two places, the model a reader already knows
     from Stripe or Linear.

     The menu is PART OF THE PAGE rather than a panel beside it: no border, no
     backdrop, no column running down to the floor, and it SCROLLS AWAY with the page
     like everything else (absolute, not fixed - a menu nailed to the glass while the
     page moves under it is exactly what makes two surfaces out of one).
     It stands NEXT TO THE CONTENT -
     the left offset is computed from the same centring the content uses, so the right
     edge of the menu meets the left edge of main exactly (132 + 1180 = 1312; below
     that width the menu simply sits at the edge and the content still starts right
     after it). The column is as narrow as the words in it: two short names need no
     more, and it reads as one body with the page rather than as a panel. When the
     names get longer, the width goes up with them. It ends where its items end, and the footer runs under it across the
     whole page - one sheet, not two.

     Minimal by design: no fills, no frames, no capsules. The active section is the
     pure --head, the rest are --faint; hover moves the tone only. Type is large (17px
     600) - it is the first thing on the page and it should read as a title, in the
     grammar of Tape and MCP. */
.gnav{position:absolute;top:0;left:max(0px,calc(50% - 656px));width:132px;z-index:40;
      display:flex;flex-direction:column;padding:20px 26px 0}
/* the brand mark moved here out of the topbar; it is the way back to the portal */
.gnav .b-home{align-self:flex-start}
/* та же пара, что в шапке и в подвале: ширина знака меньше коробки, а коробка
   держит прежний рост */
.gnav .b-logo{width:33px;height:34px}
/* THE COLUMN READS BY WEIGHT, NOT BY PIXELS ALONE */
.gnav-list{display:flex;flex-direction:column;gap:14px;margin-top:26px}
/* SAME LETTERING, BIGGER SIZE. The menu speaks the word of everything else
   that is pressed */
.gnav-item{font:600 14.5px var(--ui);color:var(--faint);text-decoration:none;
           padding:7px 0;letter-spacing:.04em;text-transform:lowercase;
           transition:color .15s}
.gnav-item:hover{color:var(--text)}
.gnav-item.active{color:var(--head);font-weight:700}
/* ── THE KITCHEN STANDS APART. Admin is not a fifth market, it is another kind
     of place, and in a plain list it read as one more section of the portal.
     The break is air plus a dot on the axis of the sections - a rule across the
     column would be a border where a breath is enough, and a hairline is not a
     language this site speaks anywhere.
     The dot is a NODE OF ITS OWN (nav.js) rather than a pseudo element of the
     link: inside the link it became part of it and a click on the dot opened
     Admin ── */
/* the dot is EXACTLY the grey of the words it stands between */
.gnav-sep{width:6px;height:6px;border-radius:50%;background:var(--faint);
          margin:10px 0 10px 1px;flex:none;pointer-events:none}
/* the build of the service that served the page, echoed under the door of the
   kitchen (nav.js builds it, and only where the kitchen itself is) */
/* the step is measured BY THE LETTERS, not by the boxes */
.nav-ver{display:block;font:400 11px/1.2 var(--ui);color:var(--faint);
         margin-top:-6px}
/* The service icons (the status dot, the theme, the sign-out) stay in the
   CORNER OF THE TOPBAR on every width */
@media (min-width:1001px){
  /* the width is reserved by the CSS rather than by the deferred nav.js,
     otherwise the content jumps on load */
  body:has(.tabs-wrap){padding-left:132px}
  body:has(.tabs-wrap) .topbar .b-home,
  body:has(.tabs-wrap) .topbar .brand > .b-logo{display:none}
  /* the height of the header is now set by the 44px button of the corner row,
     not by the line of the subheading */
  body:has(.tabs-wrap) .topbar{padding-top:15px;padding-bottom:0}
  /* ...and the CONTENT of the page opens AT THE FIRST SECTION of the menu */
  body:has(.tabs-wrap) .tabs-wrap{margin-top:11px}
  body:has(.tabs-wrap.sole) .tabs-wrap{margin-top:0}
  /* ряд без вкладок (страницы читателя: в нём только бургер телефона) воздуха
     не занимает */
  body:has(.tabs-wrap) .tabs-wrap:not(:has(.tabs)){margin-top:0}
  /* ...THE PAGE OF TEXT IS THE ONE EXCEPTION TO THAT LEVELLING */
  body:has(.tabs-wrap.sole) main{padding-top:25px}
  body:has(.tabs-wrap.sole) main > :first-child{margin-top:0}
  .tabs-wrap.sole .tabs{display:none}
  /* the footer closes the SHEET - the menu plus the content, not the window */
  body:has(.tabs-wrap) footer{
    width:calc(100% + 132px); max-width:1312px; margin-right:0;
    margin-left:max(-132px, calc((100% - 1180px) / 2 - 132px));
  }
}
@media (max-width:1000px){
  /* the sidebar folds away entirely: the sections go as the first group of
     the burger sheet (see .ns-global), and the mark with the icons returns to
     the topbar */
  .gnav{display:none}
}

/* МОБИЛЬНОЕ МЕНЮ: колонка разделов складывается в лист под бургером, а бургер
   стоит в углу шапки последним, рядом с темой и выходом; имя страницы на
   телефоне только в шапке, ряд навигации места не занимает */
.nav-burger,.nav-sheet{display:none}
@media (max-width:1000px){
  .nav-burger{display:inline-flex;align-items:center;justify-content:center;
              order:8;width:44px;height:44px;border:0;cursor:pointer;
              border-radius:14px;background:transparent;color:var(--dim);
              transition:background .15s,color .15s}
  .nav-burger:hover{color:var(--text)}
  .nav-burger[aria-expanded="true"]{background:var(--panel-hi);color:var(--text)}
  .nav-sheet{--dm-row:46px;
             display:flex;flex-direction:column;gap:6px;
             position:absolute;top:calc(100% + 8px);right:26px;
             /* the sheet of the burger is a touch wider than before */
             width:max-content;min-width:min(360px, calc(100vw - 52px));
             max-width:calc(100vw - 52px);
             z-index:40;background:var(--panel-hi);
             border-radius:18px;padding:8px;
             max-height:calc(100vh - 140px);
             max-height:calc(100dvh - 140px);   /* the address bar of mobiles */
             overflow-y:auto;
             box-shadow:var(--shadow-pop);
             transform-origin:top right;animation:navpop .16s ease}
  .nav-sheet .ns-pages{display:grid;grid-template-columns:1fr;gap:2px}
  .nav-sheet .ns-cols{columns:2;column-gap:6px}
  .nav-sheet .dm-g{break-inside:avoid}
  .nav-sheet .ns-sheet{break-inside:avoid;padding-top:6px}
  .nav-sheet .ns-sheet + .ns-sheet{margin-top:10px;padding-top:12px;
                                   border-top:1px solid var(--line2)}
  .nav-sheet .ns-cap{column-span:all;display:block;margin:0 0 4px;
                     color:var(--text2)}
  .nav-sheet .tab{display:flex;align-items:center;height:var(--dm-row);
                  padding:0 16px;border-radius:13px;
                  font:500 16px/1.2 var(--ui)}
  .nav-sheet .tab.active{background:var(--panel-top);color:var(--text)}
  .nav-sheet .cap{display:flex;align-items:flex-end;height:var(--dm-row);
                  padding:0 14px 9px;font:600 11px/1 var(--ui);
                  letter-spacing:.04em;text-transform:uppercase;
                  color:var(--faint);white-space:nowrap}
  .nav-sheet .ns-global{display:grid;grid-template-columns:1fr 1fr;gap:2px 6px;
                        padding-bottom:6px;margin-bottom:2px;
                        border-bottom:1px solid var(--line2)}
  .nav-sheet .ns-global:last-child{padding-bottom:0;margin-bottom:0;border-bottom:none}
  .nav-sheet .ns-global .cap{grid-column:1/-1}
  .nav-sheet .nav-ver{grid-column:1/-1;padding:0 14px 2px;margin-top:0}
  .nav-sheet{right:12px;max-width:calc(100vw - 24px)}   /* в лад с полями */
  .tab,.nav-burger{transition:none}
  .nav-sheet{animation:none}
  .nav-sheet .ns-pages{grid-auto-flow:row;grid-template-columns:1fr;
                       grid-template-rows:none}
  .nav-sheet .ns-cols{columns:1}
}

/* ── the topbar: the ring mark on the left with the subheading of the page next to
     it across a calm gap (on one axis with the ring), and a mirrored corner of icons
     on the right (status / theme / sign-out). The ring is an inline SVG using
     currentColor and follows the theme. There is no visible wordmark - the name of
     the brand is carried by h1.sr-only ── */
.topbar{display:flex;align-items:center;gap:16px;flex-wrap:wrap;
        max-width:1180px;margin:0 auto;padding:24px 26px 6px}
/* THE ROW OF THE TOPBAR KEEPS ITS HEIGHT. nav.js is deferred, so the theme
   button (44x44) lands AFTER the first paint */
.brand{display:flex;align-items:center;gap:14px;min-width:0;min-height:44px}
/* МАРКА ЗАДАЁТСЯ ШИРИНОЙ, А КОРОБКА ДЕРЖИТ ВЫСОТУ */
.b-home{display:inline-flex;color:inherit;text-decoration:none}
.b-home:hover .b-logo{color:var(--head)}
/* СООСНОСТЬ СЧИТАЕТСЯ ПО ЧЕРНИЛАМ, А НЕ ПО КОРОБКАМ, и двигать при этом надо
   ЗНАК, а не текст */
.b-logo{flex:none;width:33px;height:32px;color:var(--text);
        transition:color .15s}
/* имя страницы и её полстроки - одна строка одним шрифтом через точку, как
   все подписи портала; на телефоне полстроки уходят вместе с точкой */
.page-id{display:flex;align-items:baseline;gap:7px;min-width:0;flex-wrap:wrap}
.page,.tagline{font:400 13.5px var(--ui);color:var(--head)}
.page{white-space:nowrap}
.tagline::before{content:"·";margin-right:7px}
/* ── the status dot (created by ui.js): the norm is silence and the dot appears
   only on a problem. A 44x44 slot in the grid of the corner icons is always
   reserved - the corner never jumps; amber means a degradation (stale) and red
   means a break (off); the reason lives in the tooltip of the dot (on hover or a
   click) ── */
.st-wrap{position:relative;width:44px;height:44px;display:inline-flex}
.topbar .st-wrap{order:6;margin-left:auto} /* the dot opens the row of corner icons */
.st-dot{width:44px;height:44px;border:0;cursor:pointer;border-radius:14px;
        background:transparent;padding:0;display:grid;place-items:center;
        transition:background .15s}
.st-dot:hover{background:var(--hover)}
/* the norm: not only the button goes out but the hover of the whole slot too */
.st-wrap:not(.on){pointer-events:none}
.st-wrap:not(.on) .st-dot{visibility:hidden}
.st-i{width:10px;height:10px;border-radius:50%;background:var(--warn);
      position:relative}
.st-wrap.off .st-i{background:var(--down)}
/* a soft expanding ring - the live pulse of a problem */
.st-i::after{content:"";position:absolute;inset:0;border-radius:50%;
  background:inherit;animation:st-ping 2.4s cubic-bezier(0,0,.2,1) infinite}
@keyframes st-ping{0%{transform:scale(1);opacity:.5}
  70%,100%{transform:scale(2.9);opacity:0}}
@media (prefers-reduced-motion:reduce){.st-i::after{animation:none}}
/* the tooltip: a tonal card under the dot, aligned to the right edge */
/* the tooltip of the dot hangs from the RIGHT edge of its slot */
.st-pop{position:absolute;top:calc(100% + 6px);right:0;z-index:40;
  min-width:230px;max-width:300px;background:var(--panel-hi);
  border-radius:12px;padding:12px 14px;box-shadow:var(--shadow-pop);
  text-align:left;cursor:default}
.st-t{font:600 12.5px/1.35 var(--ui);color:var(--warn)}
.st-wrap.off .st-t{color:var(--down)}
.st-n{margin-top:3px;font:12px/1.45 var(--ui);color:var(--text2)}
/* the details of the status use a SINGLE 2-column grid (an auto key plus a
   1fr value) */
.st-rows{margin-top:9px;display:grid;grid-template-columns:auto 1fr;
         gap:3px 14px;align-items:baseline;
         font:11.5px/1.5 var(--ui);font-variant-numeric:tabular-nums;
         color:var(--dim)}
/* ONE FACE FOR THE WHOLE CARD. The values used to be set in mono, so four
   lines carried two families and three sizes */
.st-row{display:contents}
.st-row b{font:500 11.5px/1.5 var(--ui);color:var(--text2);text-align:right}
@media (max-width:1000px){
  /* we let the brand shrink (a long tagline wraps) */
  .brand{flex:1 1 0;min-width:0}
  /* ── THE ROW BELONGS TO THE HEADING AGAIN (04.08.2026) ─────────────────
     A phone had the clock, the initials, the role badge and the theme in the
     corner, and some forty pixels left for the name of the page - so the name
     was dropped. The corner gives the room back instead: the CLOCK GOES
     (the time is not why anyone opens a page on a phone, and the market hours
     are a desk matter), and the NAME of the signed-in user becomes the icon of
     the action it always was - the way out. What is left is the heading, and
     it wraps to a second line under the mark, aligned with it. */
  /* the selectors carry the topbar on purpose: .clock and .who-* are declared
     BELOW this block, and at equal specificity the last rule would win */
  .topbar .clock{display:none}
  /* НА ТЕЛЕФОНЕ ОСТАЁТСЯ ИМЯ, А ПОЛСТРОКИ ОБЪЯСНЕНИЯ УХОДЯТ */
  .topbar .tagline{display:none}
  .topbar .page{font-size:14px}
  .brand{align-items:center}
  .topbar .who-ini,.topbar .who-role{display:none}
  .topbar .who-out{display:block}
  /* ...AND IT IS THE SAME BUTTON AS THE OTHERS */
  .topbar .who-btn{width:44px;height:44px;padding:0;margin-right:0;
                   border-radius:14px;justify-content:center}
  .topbar .who-btn:hover,.topbar .who-btn:active{background:var(--hover)}
  .topbar .who-btn:hover .who-out,
  .topbar .who-btn:active .who-out{color:var(--text2)}
}

/* ── The tooltip (data-tip): ONE hint for the whole project. The native title was
     removed everywhere (it followed the theme of the OS rather than of the site and
     popped up immediately) - every UI hint is drawn with the panel tokens.
     On 30.07.2026 the hint moved from an ::after to ONE FLOATING NODE (UI.tip in
     ui.js; the node is a direct child of the body, position:fixed). The pseudo
     element was bound to its own element and therefore:
       - crawled off the edge of the screen on the outermost right, left and top
         elements;
       - was clipped by any ancestor with overflow:hidden (which we cured
         point-by-point, and "a card without overflow" stood as a separate note);
       - inherited the tokens of the CARD (on the light island of Home it came out
         white on white, which we cured by an exception rule);
       - did not render on SVG at all - the sparklines of streams kept the native
         title.
     The floating node removes all four: it lives in the coordinates of the screen,
     knows its boundaries and takes the tokens of the document. The positioning and
     the delay live in ui.js, here lives only the appearance ── */
.ui-tip{position:fixed;left:0;top:0;z-index:9999;max-width:min(250px,calc(100vw - 16px));
  white-space:normal;text-align:left;background:var(--panel-hi);color:var(--text);
  font:500 11.5px/1.45 var(--ui);letter-spacing:0;text-transform:none;
  border-radius:8px;padding:8px 11px;box-shadow:0 6px 18px rgba(0,0,0,.18);
  pointer-events:none;opacity:0;transition:opacity .12s ease}
.ui-tip.on{opacity:1}

/* ── the theme switcher (created by nav.js on every page): a quiet icon in the
     topbar showing the theme a click will give you ── */
.theme-btn{margin-left:auto;width:44px;height:44px;border:0;cursor:pointer;
           border-radius:14px;background:transparent;color:var(--dim);
           display:inline-flex;align-items:center;justify-content:center;
           transition:background .15s,color .15s}
.theme-btn:hover{background:var(--hover);color:var(--text2)}
/* the order in the corner: the status dot (order 6) opens the row and carries
   the auto margin to the right; on the pages without ui.js (there is no slot
   for the dot) the margin stays with the theme */
.topbar:has(.st-wrap) .theme-btn{margin-left:0}
/* ── the corner icons (the status dot, the theme, the sign-out) live in ONE box
     created by ui.js. On mobile it stands where it always did - in the right corner
     of the topbar; on the desktop nav.js moves the same box under the sections of the
     global menu - the icons are properties of the portal rather than of a page ── */
.nav-icons{display:flex;align-items:center;margin-left:auto}
/* WHO IS SIGNED IN, AND THE WAY OUT - one control instead of two */
/* no plate on hover: the initials lighting up say "this is a control" quietly
   enough, and a grey pill around a name reads as a second badge next to the
   role one */
/* the gap is TIGHTER than a row of tabs: the initials and the role are one
   thing said in two parts ("VA admin"), and six pixels made them read as two
   neighbours */
/* знак на двери: тот же рост, что в шапке - дверь это тоже страница портала
   (и та же пара размеров */
.topbar .brand-full{width:33px;height:32px;color:var(--head)}
.who-btn{display:inline-flex;align-items:center;gap:4px;border:0;cursor:pointer;
         background:transparent;padding:6px 8px;margin-right:2px;
         border-radius:12px;transition:color .15s}
/* ── TWO CAPSULES OF ONE PAIR (the owner, 06.08.2026). Who and in what role is
   ONE fact, and it used to be said in two typographies: bare initials in one
   size next to a badge in another. Now both are the same caps - one size, one
   weight, one tracking - and what tells them apart is the STEP OF THE SURFACE:
   the initials rest on --panel (one step above the header), the role on
   --panel-hi (one more). The name is the quieter of the two: the role is what
   you check, the initials only say whose it is. */
.who-ini,.who-role{font:600 9.5px var(--ui);letter-spacing:.08em;
                   text-transform:uppercase;border-radius:6px;padding:2px 5px}
.who-ini{color:var(--dim);background:var(--panel)}
.who-btn:hover .who-ini{color:var(--text2)}
/* the way out as an icon - the phone form of the same button (see the mobile
   block below); on a desktop the name says it and the icon stays off */
.who-out{display:none;color:var(--faint);transition:color .15s}
.who-btn:hover .who-out{color:var(--text2)}
.who-role{color:var(--text2);background:var(--panel-hi)}
/* КОЛЬЦО ФОКУСА - ДЛЯ КЛАВИАТУРЫ, А НЕ ДЛЯ МЫШИ */

/* ── THE CLOCK (created by ui.js): the UTC time and the session of the hour.
     ONE face for the whole row - the ui one, at the size of the initials next to
     it: the time and the session read as a single quiet line rather than as a
     mono gadget glued to a word. What mono was there for is the digits holding
     their width, and tabular-nums gives exactly that (Ubuntu already has it, a
     fallback face on another OS may not) - the row must not twitch once a
     second. The nearest opening lives in the tooltip ── */
/* the air on the LEFT is the same 12px as on the right */
.clock{display:inline-flex;align-items:baseline;gap:5px;margin:0 12px 0 12px;
       white-space:nowrap;cursor:default;
       font:500 11.5px/1 var(--ui);color:var(--faint)}
.cl-t{font-variant-numeric:tabular-nums}
.cl-s::before{content:"·";margin-right:5px}
/* the order of the corner: the status dot OPENS the row, then the clock, the
   theme, and WHO YOU ARE at the very edge */
.nav-icons .st-wrap{order:4;margin-left:0}
.nav-icons .clock{order:5}
.nav-icons .theme-btn{order:6;margin-left:0}
.nav-icons .who-btn{order:7;margin-right:0}
.nav-icons .out-btn{order:8}
.theme-btn .i-moon{display:none}
html.light .theme-btn .i-moon{display:block}
html.light .theme-btn .i-sun{display:none}

/* ── the tabs (a pill container with a tonal active one). Two levels: the pill
     holds the reading pages (Home, Prompt) and the toggles, while the data contours
     live one level below, in a tonal sheet under the "Data" tab ── */
.tabs-wrap{position:relative;max-width:1180px;margin:14px auto 0;padding:0 26px}
.tabs{display:inline-flex;gap:4px;background:var(--panel-lo);border-radius:14px;
      padding:5px}
/* THE WORD OF A TAB IS THE WORD OF A FILTER: one typography for everything
   the portal offers to press */
.tab{padding:7px 14px;border-radius:10px;color:var(--dim);text-decoration:none;
     font:600 11.5px/1.2 var(--ui);letter-spacing:.04em;text-transform:lowercase;
     white-space:nowrap;transition:background .15s,color .15s}
.tab:hover{color:var(--text2);background:var(--hover)}
.tab.active{background:var(--panel-hi);color:var(--text)}
/* the sheet of the contours keeps the grammar of the burger sheet */
/* There came to be more than a dozen contours, and a single column ran off
   below the fold like a beard */
/* Вкладка с листом - это КНОПКА, и у кнопки есть своя рамка от браузера */
.tab-data{border:0;cursor:pointer;background:transparent;
          display:inline-flex;align-items:center;gap:7px}
.tab-data .chev{transition:transform .15s}
.tab-data[aria-expanded="true"] .chev{transform:rotate(180deg)}

.data-menu{--dm-row:42px;                 /* one step of the vertical rhythm */
           position:absolute;z-index:40;width:392px;margin-top:8px;
           background:var(--panel-hi);
           /* the padding at the bottom is larger: at the top the caps label
              of a group tops the air up (its text is pressed to the bottom of
              its line), and with an equal 6px the sheet looked flattened at
              the bottom */
           border-radius:16px;padding:6px 6px 14px;box-shadow:var(--shadow-pop);
           /* ОДНА КОЛОНКА: две заводят под три страницы дыру рядом со списком */
           width:250px;
           transform-origin:top left;animation:navpop .16s ease}
/* a multicol rather than a grid: the columns BALANCE their heights by
   themselves, so a lone group leaves no hole next to a long one */
.data-menu .dm-g{break-inside:avoid}
.data-menu .tab{display:flex;align-items:center;height:var(--dm-row);
                padding:0 16px;border-radius:11px;
                font:500 14.5px/1.2 var(--ui)}
/* the sheet lies on --panel-hi, so by the shared law of elevation the selected item
   goes one step higher */
.data-menu .tab.active{background:var(--panel-top);color:var(--text)}
/* the caps captions of the classes of the contours (data / analysis) take
   EXACTLY one line of the rhythm with the text pressed to the bottom */
.data-menu .cap{display:flex;align-items:flex-end;height:var(--dm-row);
                padding:0 16px 9px;font:600 10.5px/1 var(--ui);
                letter-spacing:.08em;text-transform:uppercase;color:var(--faint)}

/* ПЕРЕЛИСТЫВАЛКА КОНТУРОВ (строит nav.js на страницах листа) */
.contour-pager{display:none}
@media (min-width:1100px){
  .contour-pager{position:absolute;right:26px;top:50%;transform:translateY(-50%);
                 display:flex;align-items:center}
  .cp-arrow{display:inline-flex;align-items:center;justify-content:center;
            padding:8px 11px;border-radius:10px;color:var(--dim);
            transition:background .15s,color .15s}
  .cp-arrow:hover{color:var(--text2);background:var(--hover)}
  /* ОДНА ТИПОГРАФИКА СО СТРОКОЙ РЯДОМ: своим кеглем перелистывалка читалась
     бы третьим голосом на строке, где уже есть пиля */
  .cp-cap{padding:0 4px 0 13px;font:600 11.5px var(--ui);
          letter-spacing:.04em;text-transform:lowercase;color:var(--faint)}
  .cp-label{display:inline-flex;align-items:baseline;gap:8px;padding:0 10px;
            font:600 11.5px/1.2 var(--ui);letter-spacing:.04em;
            text-transform:lowercase;color:var(--text);white-space:nowrap}
  /* СТОПКА ИМЁН В ОДНОЙ КЛЕТКЕ: невидимые задают ширину, поэтому зона стрелок
     закреплена самым длинным именем и не прыгает при листании */
  .cp-name,.cp-count{display:inline-grid;text-align:center}
  .cp-name>span,.cp-count>span{grid-area:1/1;white-space:nowrap}
  .cp-name>.ghost,.cp-count>.ghost{visibility:hidden}
  .cp-count{font:500 11.5px var(--ui);color:var(--text);
            font-variant-numeric:tabular-nums}
}

/* ── the base card ── */
.card{position:relative;background:var(--panel);border-radius:16px;
       padding:22px var(--pad)}

/* ── the segmented switcher (the horizons of an opinion on Home, the timeframes on
     the charts, the topics of News, the filters of the feeds and the page sizes).

     THE LAW OF ELEVATION, shared with the navigation pill (.tabs above): a capsule
     is a tray one step above its own surface, and the selected segment is one step
     above that. The active one is NEVER equal to --bg.

     The capsule used to be nailed to the pair --panel-hi / --bg while the navigation
     was nailed to --panel / --panel-hi, and neither expressed the DIRECTION of the
     elevation. It came out that in the dark theme a selected tab was lighter than
     its track while a selected segment was darker (a hole down to the background of
     the page), and in the light both flipped in different directions. On Tape two
     capsules stand 20px apart one under another and that discord was read
     point-blank: the track of the filter was brighter than the active tab of the
     navigation.
     Now on a bare background the switcher takes exactly the palette of the
     navigation, and inside a card both steps go up. The exceptions are below: the
     capsules on canvases (the charts plus the ETH outlook) and the Mono toggle
     (above - it is the only one that goes BELOW its surface) ── */
.tfswitch{display:inline-flex;gap:2px;background:var(--panel);border-radius:10px;
          padding:3px;box-shadow:var(--lift)}
/* a switch that the script builds is hidden until it exists */
.tfswitch[hidden]{display:none}
/* ...AND AN EMPTIED ONE IS NOT EMPTY ON SCREEN */
.tfswitch:empty{display:none}
/* THE CAPSULE SPEAKS IN LOWER CASE. The regime a switch names is not a title */
.tfswitch button{border:0;cursor:pointer;background:transparent;color:var(--dim);
                 font:600 11.5px var(--ui);letter-spacing:.04em;
                 padding:0 12px;height:calc(var(--ctl) - 6px);
                 border-radius:8px;text-transform:lowercase;
                 transition:background .15s,color .15s}
/* ЧУЖОЕ ИМЯ НЕ ПЕРЕПИСЫВАЕТСЯ ДАЖЕ РЕГИСТРОМ */
.tfswitch.asis button{text-transform:none;letter-spacing:0}
.tfswitch button:hover{color:var(--text2)}
.tfswitch button.active{background:var(--panel-hi);color:var(--text)}
/* НЕРЕШЁННЫЕ ЗОВУТ ДЕЙСТВИЕМ, и зовут тем же жёлтым, что метка new в строке */
/* РЯД НЕ ПРЫГАЕТ ПРИ СМЕНЕ ПОСТАВЩИКА. Состав кнопок меняется вместе с ним
   (opus/sonnet/haiku против sol/terra/luna), и без общей ширины вся строка
   дилов ездит вбок на каждом переключении */
.tfswitch.fixed button{min-width:78px}
.tfswitch.has-new button[data-v="all"]{color:var(--warn)}
.tfswitch.has-new button[data-v="all"].active{color:var(--warn)}
/* inside a card the surface is already --panel itself, so both steps shift */
.card .tfswitch{background:var(--panel-hi)}
.card .tfswitch button.active{background:var(--panel-top)}

/* ── ВЫБОР ИЗ СПИСКА (.sel) ─────────────────────────────────────────────────
   ПЕРЕНЕСЁН ИЗ OPTIONS БОЛЬШОГО СЕРВИСА (владелец, 02.09.2026). Там этот контрол
   выбирает экспирацию, здесь поставщика - жест один и тот же, и заводить второй
   его вид значило бы держать два в согласии. Строение то же: лоток несёт
   поверхность и подъём, выбранное лежит в своей лунке, шеврон нарисован рамкой,
   полка открывается под ним и поднята собственной тенью.
   ТОНА, ОДНАКО, ЗДЕШНИЕ. В большом сервисе лунка нарисована --bg, но здесь
   действует более поздний закон подъёма (.tfswitch выше): лоток на шаг выше
   своей поверхности, выбранное на шаг выше лотка, и активное НИКОГДА не равно
   --bg. Скопировать оттуда цвет значило бы притащить в новый сервис ровно ту
   дыру, ради которой закон переписывали.
   ВЫСОТА ЗАКРЫТОГО - ЗАКОН РЯДА: 3 + (--ctl - 6) + 3. */
.sel{position:relative;display:inline-flex;flex:none;background:var(--panel);
     border-radius:10px;padding:3px;box-shadow:var(--lift)}
.sel:empty{display:none}
.sel-btn{display:inline-flex;align-items:center;gap:8px;border:0;cursor:pointer;
         height:calc(var(--ctl) - 6px);padding:0 12px;border-radius:8px;
         background:var(--panel-hi);color:var(--text);
         font:500 12px/1.2 var(--ui);transition:background .15s}
.sel-btn:hover{background:var(--panel-top)}
.sel-btn::after{content:"";flex:none;width:6px;height:6px;margin-left:2px;
                border-right:1.5px solid var(--dim);
                border-bottom:1.5px solid var(--dim);
                transform:translateY(-2px) rotate(45deg)}
.sel-btn[aria-expanded="true"]::after{transform:translateY(1px) rotate(-135deg)}
/* ШИРИНА - ПО САМОМУ ШИРОКОМУ ЗНАЧЕНИЮ. Все значения лежат в ОДНОЙ клетке
   сетки, видимо одно */
.sel-v{display:grid;max-width:16ch}
.sel-v > span{grid-area:1/1;visibility:hidden;overflow:hidden;
              text-overflow:ellipsis;white-space:nowrap}
.sel-v > span.on{visibility:visible}
/* внутри карточки обе ступени уходят вверх - тот же закон, что у капсулы */
.card .sel{background:var(--panel-hi)}
.card .sel-btn{background:var(--panel-top)}
.card .sel-btn:hover{background:var(--panel-top)}
/* ПОЛКА - ПОПОВЕР: её поднимает тень, а не лестница поверхностей, поэтому она
   берёт один тон где бы ни открылась */
.sel-sheet{position:absolute;z-index:40;top:100%;left:0;margin-top:6px;
           /* полка не уже лотка: края совпадают, и открытая она читается
              продолжением кнопки, а не отдельной табличкой рядом */
           min-width:100%;box-sizing:border-box;
           max-height:min(60vh,420px);overflow:auto;
           background:var(--panel-hi);border-radius:12px;padding:6px;
           box-shadow:0 8px 20px rgba(0,0,0,.28);
           transform-origin:top left;animation:navpop .16s ease;
           display:grid;grid-template-columns:auto}
/* строка живёт display:contents, поэтому её клетки */
.sel-sheet .row{display:contents}
.sel-sheet span{display:flex;align-items:center;white-space:nowrap;height:30px;
                padding:0 12px;cursor:pointer;font:500 12.5px/1.2 var(--ui);
                color:var(--text)}
.sel-sheet .row:hover span{background:var(--hover)}
.sel-sheet .row.active span{background:var(--panel-top)}
.sel-sheet .row span:first-child{border-radius:8px 0 0 8px}
.sel-sheet .row span:last-child{border-radius:0 8px 8px 0}
/* ...А В ОДНОЙ КОЛОНКЕ ЭТО ОДНА И ТА ЖЕ КЛЕТКА, и правил на неё падает два */
.sel-sheet .row span:only-child{border-radius:8px}

/* ── the card of a collector (the pages of the contours): a grid of key facts ── */
.col-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:18px 24px}
@media (max-width:1020px){.col-grid{grid-template-columns:repeat(2,1fr)}}
.cstat{display:flex;flex-direction:column;gap:4px;min-width:0}
.cstat .lb{font:13px var(--ui);color:var(--dim)}
/* ОДНА ГАРНИТУРА НА ВЕСЬ ПРОЕКТ. Моноширинный берётся ТОЛЬКО там, где цифры
   сравнивают глазом в столбце, или где это код */
.cstat .v{font:600 15px var(--ui);font-variant-numeric:tabular-nums;
          white-space:nowrap}
.cstat .v.ok{color:var(--text)} .cstat .v.warn{color:var(--warn)}
.cstat .sub{font:11.5px var(--ui);color:var(--faint);
            font-variant-numeric:tabular-nums;
            white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
@media (max-width:1000px){.col-grid{gap:14px 16px}}

/* ── the heading of a section (shared by every page): a bold white mark ── */
/* the heading does not share its width with the caption */
/* ONE DISTANCE FROM THE BOTTOM OF A HEAD TO ITS CARD, whatever the head
   carries and however it wrapped */
.sec-head{display:flex;align-items:baseline;gap:2px 12px;flex-wrap:wrap;margin:26px 0 19px}
.sec-head:first-child{margin-top:4px}
/* THE LINE OF A TITLE IS ONE HEIGHT ACROSS THE PORTAL */
.sec-head h2{margin:0;font:700 18px var(--ui);line-height:30px;color:var(--head);
             white-space:nowrap}
/* the capsule sits in the MIDDLE of that line and out of the baseline sorting */
.sec-head .tfswitch,.sec-head .hd-sw{align-self:center}
/* УПРАВЛЕНИЕ ОХВАТА СТОИТ В КОНЦЕ СТРОКИ, а не вплотную к подписи */
.sec-head .hd-sw{margin-left:auto}
.sec-note{font:13.5px var(--ui);color:var(--dim)}
/* ДЕЙСТВИЕ ЖИВЁТ В ЗАГОЛОВКЕ СЕКЦИИ, а не в карточке под ним */
.sum-actions{margin-left:auto;display:flex;gap:8px;flex-wrap:wrap}
.sum-copy{border:0;cursor:pointer;border-radius:8px;padding:0 12px;
          height:var(--ctl);
          background:var(--panel-hi);color:var(--text2);letter-spacing:.03em;
          font:600 11.5px var(--ui);transition:background .15s,color .15s;
          min-width:132px;text-align:center;font-variant-numeric:tabular-nums}
.sum-copy:hover{background:var(--hover);color:var(--text)}
.sum-copy:disabled{opacity:.45;cursor:default}
.sum-copy:disabled:hover{background:var(--panel-hi);color:var(--text2)}
@media (max-width:1000px){
  /* на телефоне действие занимает свою строку целиком */
  .sum-actions{margin-left:0;width:100%;display:grid;
               grid-template-columns:1fr;gap:8px}
  .sum-actions .sum-copy{text-align:center;min-width:0}
}
/* A LINK IN THE QUIET LINE OF A SECTION keeps the line a caption rather than
   a call to action */
.sec-note a{color:var(--text2);text-decoration:underline;
            text-decoration-color:var(--line);text-underline-offset:3px}
.sec-note a:hover{color:var(--text);text-decoration-color:var(--dim)}

/* ── the table card (.vt): the entities go as rows; on narrow screens a row turns
     into a block with a grid of captioned cells (the caption comes from data-l). The
     1020 collapse breakpoint is THE SINGLE table breakpoint of the site (as with the
     Levels matrix and Closed minutes on Streams): the wide tables go into blocks
     BEFORE a horizontal scroll would appear ── */
.tcard{padding:16px 0 8px}
/* показания НАД таблицей в одной карточке: у таблицы отступы дают ячейки, а
   строка показаний своих не имеет и без этого правила легла бы на самый край */
.raw-top{padding:6px var(--pad) 16px}
/* ── ПАНЕЛЬ НАД ТАБЛИЦЕЙ: поиск, счёт и мелкое действие ────────────────────
   Перенесено из портала (кухня новостей), где жило стилем одной страницы.
   Строка сужает набор, а не листает его: набранное слово оставляет в таблице
   только то, что ему отвечает, и счётчик рядом говорит, сколько осталось. */
.tb-tools{display:flex;align-items:center;gap:8px;flex-wrap:wrap;
          padding:0 var(--pad) 12px}
.tb-find{flex:0 1 210px;min-width:120px;border:0;border-radius:9px;
         background:var(--panel-hi);color:var(--text);
         font:400 12.5px var(--ui);padding:0 12px;height:var(--ctl)}
.tb-find::placeholder{color:var(--faint)}
.tb-find:focus{outline:2px solid var(--line2);outline-offset:0}
.tb-tools .sp{flex:1}
.tb-count,.tb-lb{font:600 11px var(--ui);color:var(--faint);letter-spacing:.03em;
                 font-variant-numeric:tabular-nums}
/* ТРИ ГЛАГОЛА ПЕРЕНОСЯТСЯ ВМЕСТЕ, А НЕ ПО ОДНОМУ */
.tb-acts{display:inline-flex;gap:8px;flex:none}
/* ── СПИСОК ИСТОЧНИКОВ: РЕШЕНИЕ, А НЕ ПЕРЕЧЕНЬ ────────────────────────────
   Сорок имён по алфавиту - это список, который никто не читает; по ОБЪЁМУ он
   становится списком решений: первые пять несут две трети ленты, а хвост - по
   истории на брата. Доля стоит рядом со счётом по той же причине: "779" не
   значит ничего, пока не станет "31% всего, что мы показываем".
   ПОЛОСКА - ТА КОЛОНКА, КОТОРУЮ ГЛАЗ ЧИТАЕТ НА САМОМ ДЕЛЕ: проценты в столбце
   все на одно лицо, а полоска говорит "это треть твоей ленты", даже если её не
   читать. Висит под своим числом, у правого края колонки. */
.np-bar{display:block;height:3px;border-radius:2px;background:var(--text2);
        margin:4px 0 0 auto;min-width:1px}
/* ВЫКЛЮЧЕННЫЙ ИСТОЧНИК ОСТАЁТСЯ ЧИТАЕМЫМ - это решение, а не удаление, и его
   пересматривают так же часто, как принимают */
.vt tr.off .tick-name{color:var(--faint)}
.vt tr.off td{opacity:.55}
/* ГАЛОЧКА ЖИВЁТ В КЛЕТКЕ ИМЕНИ, а не в своей колонке */
.vt td.np-cell{display:flex;align-items:center;gap:9px}
/* НЕРЕШЁННЫЙ ИСТОЧНИК ЗОВЁТ РЕДАКТОРА: строка тихая, как у выключенного (она
   делает то же самое */
.np-badge{flex:none;padding:2px 6px;border-radius:5px;
          font:600 9px/1 var(--ui);letter-spacing:.07em;text-transform:uppercase;
          background:var(--hover);color:var(--faint)}
.np-badge.new{color:var(--warn);
              background:color-mix(in srgb,var(--warn) 14%,transparent)}
.vt tr.off .np-badge.new{opacity:1}
/* мелкое действие панели: тот же жест, что у кнопки копии, только без ширины */
/* ОДНА МЕЛКАЯ КНОПКА НА ВСЮ КУХНЮ: глагол панели инструментов (take all) и
   действие в строке списка (switch off, delete) */
.tb-bulk,.u-act button{border:0;cursor:pointer;background:var(--panel-hi);
         color:var(--dim);letter-spacing:.03em;font:600 11px var(--ui);
         padding:0 12px;height:var(--ctl);border-radius:9px;
         transition:background .15s,color .15s}
.tb-bulk:hover,.u-act button:hover{background:var(--hover);color:var(--text)}
.tb-bulk[disabled]{opacity:.35;cursor:default}

/* фильтр не совпал ни с чем: одна строка там, где были бы строки */
td.tb-none{text-align:center;color:var(--faint);font:400 12.5px var(--ui);
           padding:22px 12px}
.twrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
table.vt{width:100%;min-width:760px;border-collapse:collapse;font-variant-numeric:tabular-nums}
/* the head of the columns: small caps with letter-spacing */
.vt th{font:600 11px var(--ui);color:var(--text2);text-transform:uppercase;
       letter-spacing:.07em;text-align:right;padding:6px 12px;white-space:nowrap}
.vt th:first-child{text-align:left;padding-left:var(--pad)}
.vt td{font:12.5px var(--ui);text-align:right;padding:9px 12px;white-space:nowrap;
       vertical-align:top;border-top:1px solid var(--line2)}
/* the first column is the label of a row: it has a typeface of its own (ui
   rather than mono) but THE SAME SIZE as the data (12.5) */
.vt td:first-child{font:500 12.5px var(--ui);color:var(--text);text-align:left;
                   padding-left:var(--pad)}
.vt td:last-child,.vt th:last-child{padding-right:var(--pad)}
.vt .prod{display:block;font:11.5px var(--ui);color:var(--faint);margin-top:2px}
.vt .d{display:block;font-size:11px;color:var(--faint);margin-top:2px}
@media (max-width:1020px){
  .twrap{overflow:visible}
  table.vt{min-width:0;display:block}
  .vt thead{display:none}
  .vt tbody{display:block}
  .vt tr{display:grid;grid-template-columns:repeat(3,1fr);gap:12px 14px;
         padding:14px 16px;border-top:1px solid var(--line2)}
  .vt tr:first-child{border-top:none}
  /* the data is noticeably larger on a phone: there is one screen, and small type
     is a barrier */
  .vt td{display:block;text-align:left;padding:0;border:0;white-space:normal;
         font-size:15px}
  .vt .d,.vt .prod{font-size:12.5px}
  .vt td::before{content:attr(data-l);display:block;font:600 11px var(--ui);
                 text-transform:uppercase;letter-spacing:.06em;
                 color:var(--faint);margin-bottom:3px}
  .vt td:first-child{grid-column:1/-1;padding:0;font-size:15.5px}
  .vt td:first-child::before{content:none}
}

/* ── Health: one zone for the problems of a page - the sources go as status
     columns (a small-caps name rhyming with the heads of the tables plus a quiet
     line of the state), and the error log is always the last block, across the full
     width behind a hairline; the norm is silence ── */
.card.health-card{padding:20px 0 14px;display:flex;flex-direction:column}
.health-card.loading{min-height:148px}
/* the blocks go as a plain list across the full width (not as columns) with a
   hairline between them; the error log is the same kind of block, uniformly */
.hblock{padding:2px var(--pad)}
.hblock + .hblock{border-top:1px solid var(--line2);margin-top:12px;padding-top:14px}
.hblock .gv{font:600 11px var(--ui);color:var(--text2);text-transform:uppercase;
            letter-spacing:.07em;margin-bottom:7px}
/* ── THE TICK: one checkbox for the whole kitchen ────────────────────────
   A control drawn by CSS alone - no image, no font, nothing to load - and it
   scales with its box. The mark is two borders of an empty box turned 45
   degrees, so it reads the same in both themes without a second rule.
   It lived inside the News page while it had one user (26.08.2026); the Notify
   page needed the same tick, and a control copied into a second page is a
   control that drifts on the first day somebody adjusts one of them. */
.tick{appearance:none;-webkit-appearance:none;position:relative;flex:none;
       width:16px;height:16px;margin:0;cursor:pointer;
       border:1.5px solid var(--line2);border-radius:5px;background:transparent;
       transition:background .12s ease,border-color .12s ease}
.tick:hover{border-color:var(--dim)}
.tick:checked{background:var(--text);border-color:var(--text)}
.tick:checked::after{content:"";position:absolute;left:4.4px;top:1.4px;
       width:3.6px;height:8px;border:solid var(--bg);
       border-width:0 1.7px 1.7px 0;transform:rotate(45deg)}
.tick:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* THE BOX AND ITS WORD ARE ONE TARGET: the label is what makes the name
   clickable, and the name is what a reader aims at */
/* THE PAIR BREATHES, AND ONLY JUST. The name of a box is BOLD, and a bold
   word pulls at the box harder than an ordinary one */
.tick-row{display:inline-flex;align-items:center;gap:12px;cursor:pointer}
.tick-name{font:600 12.5px var(--ui);color:var(--text)}
.tick-row:hover .tick-name{color:var(--head)}

/* ── THE DIALS OF A KITCHEN ──────────────────────────────────────────────
   A kitchen card is rows of dials, and a row is groups of "a word and the
   thing the word names". The word stands NEXT TO its control, never in a
   column of its own: a column pushes every control to the same inner edge and
   the card reads as a form somebody centred rather than as a sentence about
   what the contour does.
   It grew on the News page and stayed there while it had one reader
   (26.08.2026); the Notify page needed the same rows, so the grammar moved
   here under a name that says what it is. The `.sc-` of mcpadmin/almadmin is a
   DIFFERENT thing (a warning card) - one of the reasons this could not simply
   keep the old prefix. */
/* THE TWO-CLASS FORM IS LOAD-BEARING. The phone rule `.card{padding:18px
   16px}` is written far below every one of these and has the same weight, so
   a single class lost to it there and only there */
.card.dial-card{padding:0}          /* the rows carry the padding, not the card */
.dial-read{padding:22px var(--pad) 20px}          /* the readings above the dials */
.dials{display:flex;align-items:center;gap:12px;flex-wrap:wrap;
       padding:15px var(--pad);border-top:1px solid var(--line2)}
/* ВТОРОЙ ЭТАЖ ТОГО ЖЕ РЯДА, а не второй ряд */
.dials.floor{border-top:0;padding-top:0}
/* a card whose first row IS the row: it needs the air of a card, not of a foot */
.dial-card > .dials:first-child{border-top:0;padding:20px var(--pad)}
.dials .d{font:12.5px var(--ui);color:var(--faint)}
/* THE WORDS THAT NAME THE ROWS STAND IN A COLUMN, so the controls they name
   start on one line */
.dial-card .dials > .dial > .d:first-child{min-width:70px}
.dials .sp{flex:1}
/* A LABEL AND THE DIAL IT NAMES ARE ONE BOX: the row may wrap, but never
   between a word and the thing it is a word for */
.dial{display:inline-flex;align-items:center;gap:12px;flex-wrap:wrap}
.dial-div{width:1px;align-self:stretch;background:var(--line2);margin:0 8px}
/* THE SPINNERS ARE OFF in both engines: a number field of the portal is typed
   into, never nudged */
/* ВСЕ КОНТРОЛЫ ОДНОГО РЯДА - ОДНОЙ ВЫСОТЫ */
.dial-n{width:58px;border:0;border-radius:9px;background:var(--panel-hi);
        color:var(--text);font:600 12.5px var(--ui);padding:0 10px;
        height:var(--ctl);
        font-variant-numeric:tabular-nums;
        text-align:center;appearance:textfield;-moz-appearance:textfield}
.dial-n::-webkit-outer-spin-button,
.dial-n::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.dial-n:focus{outline:2px solid var(--line2);outline-offset:0}

.gap-row{display:flex;gap:16px;font:12.5px var(--ui);color:var(--text2);
         font-variant-numeric:tabular-nums;padding:3px 0}
/* THE TRAFFIC LIGHT STANDS ON THE VALUE, NEVER ON THE NAME */
/* ХОРОШЕЕ НЕ ПИШЕТСЯ ЦВЕТОМ. Норма это норма: она набирается тем же цветом,
   что и всё остальное на странице */
.gap-row .ok{color:var(--text)} .gap-row .warn{color:var(--warn)}
.gap-row .bad{color:var(--down)}
/* recent errors use the same 12.5 as the rest of the health data */

/* ── AN EMPTY STATE THAT STANDS IN A READING COLUMN ───────────────────────
   A plate that has nothing in it centres its message, and that is right: the
   message IS the whole plate. A feed has no plate - it is a column of text with
   a left edge the eye is already on - and a notice in the middle of eleven
   hundred pixels reads as belonging to the page rather than to the feed (the
   owner, 20.08.2026).
   So in a column it stands WHERE THE FIRST ENTRY WOULD STAND, and it is set as
   an entry: the line that says what happened takes the size of a headline, the
   line that explains takes the size of the body. One modifier, two feeds (News
   and Tape), one behaviour. */
/* ── AN EMPTY STATE THAT STANDS IN A READING COLUMN ───────────────────────
   A plate that has nothing in it centres its message, and that is right: the
   message IS the whole plate. A feed has no plate - it is a column of text with
   a left edge the eye is already on - and a notice in the middle of eleven
   hundred pixels reads as belonging to the page rather than to the feed (the
   owner, 20.08.2026).
   So in a column it stands WHERE THE FIRST ENTRY WOULD STAND, and it is set as
   an entry: the line that says what happened takes the size of a headline, the
   line that explains takes the size of the body. One modifier, two feeds (News
   and Tape), one behaviour. */
.nquiet{padding:40px 24px;text-align:center}
.nquiet .t{font:700 16px var(--ui);color:var(--text);letter-spacing:.01em}
.nquiet .n{margin-top:6px;font:12.5px var(--ui);color:var(--faint)}
/* the links in a quiet scene use the tokens of the site rather than the default
   blue and purple */
.nquiet a{color:var(--text2);text-decoration:underline;text-underline-offset:2px}
.nquiet a:hover{color:var(--text)}
.nquiet.column{padding:22px 0 0;text-align:left}
.nquiet.column .t{font:700 18px/1.4 var(--ui)}
.nquiet.column .n{margin-top:6px;font:400 16px/1.55 var(--ui);color:var(--text2)}
/* ── the centring of an empty state inside a card (shared across the whole
   project): a card holding a .nquiet becomes a flex column; the ancestor container
   carrying the .nquiet is stretched over all the free height and centred vertically
   - the headers and the counters (feed-head, sum-top ...) stay at the top, since
   they have no .nquiet. The gate by :has(.nquiet) leaves a filled state (rows or a
   grid) untouched. It covers .table-card (Closed minutes) too - the only plate that
   is not a .card ── */
.card:has(.nquiet){display:flex;flex-direction:column}
.card:has(> .nquiet){justify-content:center}
.card:has(.nquiet) > *:has(.nquiet){
  flex:1;display:flex;flex-direction:column;justify-content:center}
@media (max-width:1000px){.nquiet{padding:32px 16px}}

/* ── A PLATE OF TEXT THAT SHIPS WITH THE CODE ─────────────────────────────
   A contract the model is given, shown byte for byte with a button to take it
   away. Written for the AI opinions page and needed a second time the day the
   News contour got a rubric of its own (20.08.2026), so it moved here: the
   heading row, the body and the typography of the text are the same thing on
   both pages, and a second copy would have drifted the first time either was
   touched. What stays with a page is what is ITS own - the collapse toggle of
   the four heavy plates on AI opinions, the widths of its buttons. */
.card.pr-card{padding:0}   /* no overflow:hidden - it would clip a sheet opened over it */
.pr-top{position:relative;display:flex;align-items:baseline;gap:10px;
        padding:18px 24px 4px;flex-wrap:wrap}
.pr-top .t{font:600 14px var(--ui);color:var(--text)}
/* the version and the date are an equal part of the heading */
.pr-top .u{font:inherit;color:inherit;font-variant-numeric:tabular-nums}
.pr-top .sp{flex:1}
.pr-body{padding:6px 24px 18px}
.pr-text{font:14px/1.65 var(--ui);color:var(--text);white-space:pre-wrap;
         overflow-wrap:anywhere}
.pr-text.quiet{color:var(--faint)}
/* A HEAVY PLATE COLLAPSES to its own heading: a sheet of contract is worth
   opening, not worth scrolling past */
.clp-tg{background:none;border:0;padding:0;cursor:pointer;align-self:center;
        font:600 14px/1 var(--mono);width:12px;text-align:center;
        color:var(--text2);transition:color .15s}
.clp-tg:hover{color:var(--text)}
.pr-top .t[data-clp]{cursor:pointer}
.card.clp .pr-body{display:none}
.card.clp .pr-top{padding-bottom:16px}
.card.clp.loading{min-height:0}

.sum-copy{border:0;cursor:pointer;border-radius:8px;padding:6px 12px;
          background:var(--panel-hi);color:var(--text2);letter-spacing:.03em;
          font:600 11.5px var(--ui);transition:background .15s,color .15s;
          min-width:132px;text-align:center;font-variant-numeric:tabular-nums}
.sum-copy:hover{background:var(--hover);color:var(--text)}
.sum-copy:disabled{opacity:.45;cursor:default}
.sum-copy:disabled:hover{background:var(--panel-hi);color:var(--text2)}
a.sum-copy{text-decoration:none;display:inline-block}
/* ── the loading skeleton: until the first answer of the backend the content is
     hidden (the geometry is preserved so nothing jumps) while the plate itself
     pulses quietly - a slow "breath in, breath out" instead of a shimmer. The JS
     removes the `loading` class after the first successful render of the data. ── */
.loading{position:relative;   /* it works on non-.card containers too */
  animation:skel-pulse 2.6s ease-in-out infinite}
/* ПОЯВЛЕНИЕ ПЛАВНОЕ, А НЕ РЫВКОМ. Переход объявлен на самих потомках, а не
   внутри .loading */
.card > *,main > *,footer{transition:opacity .3s ease}
.loading > *{opacity:0}
/* ПУСТОЙ СКЕЛЕТ ВСЁ РАВНО ЗАНИМАЕТ МЕСТО. Контейнер, который скрипт ещё не
   наполнил, схлопнулся бы в ноль, и страница подпрыгнула бы в момент, когда
   данные приехали */
.loading:empty{min-height:148px;border-radius:16px;background:var(--panel)}
@keyframes skel-pulse{0%,100%{opacity:1}50%{opacity:.55}}
@media (prefers-reduced-motion:reduce){
  .loading{animation:none;opacity:.75}
}

/* ── the footer: a quiet typographic signature, shared by every page - a hairline,
     the mark plus the version pill, and the motto on the line below ── */
/* ГЕОМЕТРИЯ СТРАНИЦЫ ОДНА НА ВСЕХ: она стояла копией в <style> семи страниц,
   и любая правка требовала семи одинаковых */
main{max-width:1180px;margin:0 auto;padding:22px 26px 88px}
@media (max-width:1000px){main{padding:18px 10px 56px}}
footer{max-width:1180px;margin:0 auto;padding:22px 26px 44px}
.f-inner{border-top:1px solid var(--line2);padding-top:24px;
         display:flex;flex-direction:column;align-items:center;gap:9px}
.f-brand{display:inline-flex;align-items:center;gap:10px}
/* в подвале тот же приём, что в шапке: 15 в ширину при коробке в 16 */
.f-logo{flex:none;width:21px;height:16px;color:var(--text2)}
/* the version is a quiet mono tag rather than a statement */
.f-ver{font:11px/1 var(--ui);color:var(--dim);background:var(--panel);
       font-variant-numeric:tabular-nums;
       border-radius:999px;padding:4px 10px}
.f-ver:empty{display:none}
/* the caption under the "logo plus version" line */
.f-note{font:11.5px var(--ui);color:var(--faint);text-align:center}
/* the notice inside the signature: the same ink as the sentence it sits in,
   marked by a rule rather than by a colour */
.f-note a{color:inherit;text-decoration:underline;text-underline-offset:2px}
.f-note a:hover{color:var(--text2)}
.sr-only{position:absolute;width:1px;height:1px;overflow:hidden;
         clip:rect(0 0 0 0);white-space:nowrap}
@media (max-width:1000px){
  .tabs-wrap{position:relative;display:flex;align-items:center;
             justify-content:space-between}
  .tabs{display:none}
  /* An open desktop sheet of the contours MUST disappear on a narrow screen */
  .data-menu{display:none}
}
@media (max-width:1000px){
  /* the margins at the edges of the screen are narrower (12px) */
  .topbar{padding:20px 12px 0}
  .tabs-wrap{padding:0 12px;margin-top:0}   /* на телефоне ряд - только якорь листа */
  /* ...AND THE CONTENT TAKES THE SAME TWELVE */
  body main{padding-left:12px;padding-right:12px}   /* in tune with the margins
                                                           of the container */
  :root{--pad:16px}
  .card{padding:18px var(--pad)}   /* denser on a phone - less empty scrolling */
  /* the cards with an INTERNAL grammar of margins (the rows and the blocks
     carry their own 16px on the sides */
  .tcard{padding:16px 0 8px}
  .health-card{padding:20px 0 14px}
  /* ...and the card of a CONTRACT is the fourth of exactly the same case,
     missed when the list was written */
  .pr-card{padding:0}
  /* ...and the card of DIALS is the fifth{padding:0}` lived in the page it
     was linked AFTER theme.css and won on its own; standing here it is above
     the mobile shortcut at equal specificity, so the shortcut won it back and
     the two paddings stacked */
  .dial-card{padding:0}
  /* ── THE DIALS STAND IN A COLUMN HERE ────────────────────────────────
     A row of groups is a row while there is a row to be had; on a phone there
     is not, and wrapping it left the groups at ragged starts with a hairline
     between two of them that no longer parted anything. One group to a line,
     all flush left - and the hairline and the spring go with the row they
     belonged to: a vertical rule between two stacked things is not a rule, and
     a spring in a column pushes nothing.
     The card is denser too: .dial-card{padding:0} keeps the shortcut of .card
     from reaching it, so the rows take the canon's number themselves. */
  .dial-read{padding:18px 16px 16px}
  .dials{padding:14px 16px;flex-direction:column;align-items:flex-start;gap:14px}
  .dial-card > .dials:first-child{padding:18px 16px}
  .dial-div,.dials .sp{display:none}
  .dial.head{flex-direction:column;align-items:flex-start;gap:12px}
  /* and its rows take the 16 of the phone, the same step .sum-top took above */
  .pr-top{padding:18px 16px 4px}
  .pr-body{padding:6px 16px 18px}
  .card.clp .pr-top{padding-bottom:16px}
  footer{padding:20px 12px 36px}
  .tfswitch button{padding:4px 7px;font-size:11px}
  /* the capsule is shorter here, and the line of a title is its height */
  .sec-head h2{line-height:27px}
}
/* ── ONE RHYTHM INSIDE EVERY HEAD OF THE PORTAL ─────────────────────────────
   A head is a title, a caption under it and, on some sections, a control. The
   air between its lines is ONE number (the row gap above), and the air under it
   is one number (.sec-head), whatever the head carries.
   Two editions got this wrong by treating the control as a line of its own.
   Giving heads with a control a bigger row gap (10px against 2px) pushed their
   CAPTION away from the title - side by side, `Contract` read tight and
   `Through time` loose, and that is the same misprint one line up (owner,
   14.08.2026). Subtracting the height of the control from the margin under the
   head only moved the problem to the phone, where the control ends the head.
   THE CONTROL IS NOT A LINE, IT IS THE RIGHT SIDE OF THE TITLE. Where the whole
   head fits one line it already stood there; where it does not, the CAPTION is
   what goes down - it is the long part - and the control stays up beside the
   title. So every head of the portal, on any width, reads the same way: title,
   caption under it, card under that. */
@media (max-width:1200px){
  .sec-head .sec-note{flex-basis:100%;order:2}
  .sec-head .tfswitch,.sec-head .hd-sw{order:1}
}
@keyframes navpop{from{opacity:0;transform:scale(.97) translateY(-4px)}}
@media (prefers-reduced-motion:reduce){
  .tab{transition:none}
}
/* ...and the tab that leads to it disappears from the pill of the section */

/* ── the quiet sign-out icon (the closed services: on app nav.js adds it by the
     nav=app cookie, the admin has markup of its own): the grammar of theme-btn ── */
.out-btn{width:44px;height:44px;border:0;cursor:pointer;border-radius:14px;
         background:transparent;color:var(--dim);
         display:inline-flex;align-items:center;justify-content:center;
         transition:background .15s,color .15s}
.out-btn:hover{background:var(--hover);color:var(--text2)}
/* The order of the corner of a SERVICE page (the admin of the users) */
.topbar > .theme-btn{order:7}
.topbar > .out-btn{order:8}

/* ── the curtain of the first load (.veil, the early script of the pages): the
     content does not flash through in pieces - it appears whole once every visible
     plate has dropped its skeleton (nav.js watches it; there is a timeout as
     insurance - with a dead contour we show the skeletons).
     THE CURTAIN COVERS THE CONTENT, NOT THE FRAME (the owner, 10.08.2026). It used
     to hold the WHOLE body, so the frame of the portal - the topbar, the pill and
     the menu of the sections - waited for the data of a page it does not depend on
     and flashed in half a second later. The frame is known before any request and
     STANDS STILL, so it is drawn at once.
     THE FOOTER GOES WITH THE CONTENT (the owner, the same day): it is known too,
     but it does not stand still - it rests on the bottom of main, and until the
     plates have their height it sits wherever the short page leaves it. Drawn at
     once, it would show up under the topbar and then travel down the screen.
     The <html> holds the background: a body at zero opacity must not reveal a white
     bottom.
     ПОПЫТКА СНЯТЬ ЗАНАВЕС С main ОТМЕНЕНА В ТОТ ЖЕ ДЕНЬ (владелец, 02.09.2026:
     "нет, не только footer, это контент"). Раздельная отрисовка выглядит хуже
     целой: заголовки встают сразу, плашки доезжают по одной, и мигает уже вся
     страница, включая раму. Содержимое - это ВСЁ, что под шапкой, и появляется
     оно разом. Ждать при этом стало 0.3 вместо 0.5. */
html{background:var(--bg)}
main,footer{transition:opacity .18s ease}
/* ЗАНАВЕС НАДЕВАЕТСЯ МГНОВЕННО, А СНИМАЕТСЯ ПЛАВНО */
html.veil main,html.veil footer{opacity:0;transition:none}

/* ── ON A PHONE A TABLE STOPS BEING A TABLE ────────────────────────────────
   Three columns in three hundred points give a middle column six lines tall and
   two words wide - the reader spells it out instead of reading it. So below this
   width every row becomes a small block, one cell under another. The header goes
   with the columns: it named them, and there are no columns left to name. */
@media (max-width:760px){
  .doc table{margin-bottom:22px}
  .doc thead{display:none}
  .doc tbody,.doc tr,.doc td{display:block;width:auto}
  .doc tr{border-bottom:1px solid var(--line2);padding:13px 0}
  .doc tr:first-child{padding-top:0}
  .doc td{border:0;padding:0}
  .doc td:first-child{margin-bottom:3px}
}

/* ══ СТРАНИЦЫ ДВЕРИ, СТОЛА И ОГЛАВЛЕНИЯ ═══════════════════════════════════
   ПЕРЕНЕСЕНО ИЗ РАЗМЕТКИ */

/* ── дверь и стол: форма входа, одна на двоих ───────────────────────────── */
/* ГЕОМЕТРИЯ ВХОДА ОДНА: колонка flex, main занимает всё под шапкой */
body:where(.p-door,.p-desk){min-height:100vh;display:flex;
                            flex-direction:column;margin:0}
/* автоматические поля шапки в колонке flex сняли бы растяжку - держим явно */
:where(body.p-door,body.p-desk) .topbar{width:100%}
:where(body.p-door) main{flex:1;display:flex;align-items:center;
                         justify-content:center;padding:22px 26px 88px}
/* ИСКЛЮЧЕНИЕ ИЗ ОБЩЕЙ ГЕОМЕТРИИ (main выше): страница стола тянет форму по
   высоте и центрирует её. Ширина и отступы */
:where(body.p-desk) main{flex:1;display:flex;flex-direction:column;width:100%}
#login_view{flex:1;display:flex;justify-content:center;align-items:center}
#login_view[hidden]{display:none}   /* display:flex сильнее [hidden] - гасим явно */

.login-card{width:min(360px,calc(100vw - 40px));padding:26px 28px 24px}
.login-card .mark{margin:0;font:700 19px var(--ui);color:var(--head)}
.login-card .tagline{display:block;margin-top:3px;font:12.5px var(--ui);
                     color:var(--dim)}
.lg-field{margin-top:14px}
.lg-field label{display:block;font:600 11px var(--ui);letter-spacing:.06em;
                text-transform:uppercase;color:var(--faint);margin-bottom:6px}
.lg-field input{width:100%;box-sizing:border-box;border:1px solid var(--line);
                border-radius:10px;background:var(--bg);color:var(--text);
                font:14px/1.4 var(--ui);padding:10px 12px}
.lg-field input:focus{outline:2px solid var(--faint);outline-offset:1px}
/* в светлой поле и так читается лункой (--bg на --panel) - рамка лишняя */
html.light .lg-field input,html.light .u-panel input,
html.light .add-row input{border-color:transparent}
.lg-btn{margin-top:18px;width:100%;border:0;cursor:pointer;border-radius:14px;
        padding:13px 0;background:var(--panel-hi);color:var(--text);
        font:600 14px var(--ui);transition:background .15s,color .15s}
.lg-btn:hover{background:var(--hover)}
.lg-btn[disabled]{color:var(--dim);cursor:default}
.lg-err{margin:12px 0 0;min-height:17px;font:12.5px var(--ui);color:var(--warn)}

/* ── стол: список пользователей ─────────────────────────────────────────────
   Строка - имя плюс подпись подстрокой (грамматика матрицы Levels), действия
   справа. Удаление и установка подтверждаются вторым нажатием, ширина
   закреплена, и "sure?" не двигает строку. */
/* СПИСОК СТРОК С ДЕЙСТВИЯМИ - канон проекта (стол, маршруты Notify) */
.list-card{padding:8px 0 10px;min-height:96px}
.u-row{padding:13px var(--pad);border-top:1px solid var(--line2)}
.u-row:first-child{border-top:none}
.u-line{display:flex;align-items:center;gap:12px}
.u-name{font:700 14px var(--mono);color:var(--text);overflow-wrap:anywhere}
.u-sub{display:block;margin-top:3px;font:11.5px var(--ui);color:var(--faint);
       font-variant-numeric:tabular-nums}
.u-sub.warn{color:var(--warn)}
.u-main{flex:1;min-width:0}
/* действия стоят плашками (правило .tb-bulk выше) с тем же воздухом, что у
   глаголов панели инструментов (.tb-acts) */
/* ДЕЙСТВИЯ РЯДА ОДНОЙ ШИРИНЫ. Колонки сетки равны, но Chrome выравнивает их
   не на первом кадре (ширину auto-сетки он считает то суммой, то «широкое ×
   n»), поэтому ровность держит порог: ни одна плашка ряда не уже самого
   длинного глагола портала ("make admin", 80 px) - ряд ровный с первого кадра */
.u-act{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;gap:8px;flex:none}
.u-act button{width:100%;min-width:82px;white-space:nowrap}
.u-act button.arm{background:var(--hover);color:var(--warn)}
/* "SURE?" НЕ ДВИГАЕТ КНОПКУ: оба слова лежат в одной клетке, видно одно, и
   ширину с первого кадра задаёт широкое - тот же приём, что у выпадайки */
.u-act button,.u-set{display:grid;place-items:center}
.u-act button>span,.u-set>span{grid-area:1/1}
.u-act button>.sure,.u-set>.sure{visibility:hidden}
.u-act button.arm>.sure,.u-set.arm>.sure{visibility:visible}
.u-act button.arm>span:not(.sure),.u-set.arm>span:not(.sure){visibility:hidden}
/* человек за логином стоит сразу после него, тихим цветом */
.u-human{margin-left:8px;font:500 12.5px var(--ui);color:var(--dim)}
/* ПЛАШКА РОЛИ СТОИТ РЯДОМ С ИМЕНЕМ: тихие капсы у пользователя, акцент
   проекта у админа */
.u-role{margin-left:8px;font:600 10px var(--ui);letter-spacing:.08em;
        text-transform:uppercase;color:var(--faint)}
.u-role.on{color:var(--warn)}
/* ПАНЕЛЬ ИМЕНИ ТЯНЕТСЯ НА ВСЮ КАРТОЧКУ, а не на текстовую колонку строки */
.u-name-panel{margin-left:-24px;margin-right:-24px;
              width:calc(100% + 48px);padding:0 12px}
.u-name-panel input{flex:1;min-width:0}
/* встроенная панель смены пароля (её открывает reset) */
.u-panel{display:flex;gap:8px;margin-top:10px}
.u-panel[hidden]{display:none}
.u-panel input{flex:1;min-width:0;border:1px solid var(--line);border-radius:10px;
               background:var(--bg);color:var(--text);font:13px/1.4 var(--ui);
               padding:8px 11px}
.u-panel input:focus{outline:2px solid var(--faint);outline-offset:1px}
.u-panel .u-set{border:0;cursor:pointer;border-radius:8px;padding:6px 12px;
                background:var(--panel-hi);color:var(--text2);letter-spacing:.03em;
                font:600 11.5px var(--ui);min-width:58px;
                transition:background .15s,color .15s}
.u-panel .u-set:hover{background:var(--hover);color:var(--text)}
.u-panel .u-set.arm{background:var(--hover);color:var(--warn)}
/* пустое место набирается жирным - правило проекта, как в News */
.u-quiet{padding:22px 24px;font:600 13px var(--ui);color:var(--text2)}

/* ── стол: карточка заведения. Поля и кнопка в ряд, а на узком - колонкой ── */
.add-card{padding:18px 24px}
.add-row{display:flex;gap:10px;align-items:center}
.add-row input{flex:1;min-width:0;border:1px solid var(--line);border-radius:10px;
               background:var(--bg);color:var(--text);font:13.5px/1.4 var(--ui);
               padding:9px 12px}
.add-row input:focus{outline:2px solid var(--faint);outline-offset:1px}
.add-btn{border:0;cursor:pointer;border-radius:10px;padding:9px 18px;flex:none;
         background:var(--panel-hi);color:var(--text);font:600 12.5px var(--ui);
         transition:background .15s,color .15s}
.add-btn:hover{background:var(--hover)}
.add-btn[disabled]{color:var(--dim);cursor:default}
.add-err{margin:10px 0 0;min-height:16px;font:12px var(--ui);color:var(--warn)}
/* основание значка выхода и порядок в углу - выше, в общем разделе шапки */
.out-btn[hidden]{display:none}

/* ── оглавление кухни ───────────────────────────────────────────────────────
   БЕЗ ПЛАШЕК. Восемнадцать заполненных карточек были восемнадцатью рамками
   вокруг восемнадцати коротких фраз: глаз читал коробки первыми, а слова
   вторыми (владелец, 04.08.2026). Ссылка - это текст: имя и полстроки под ним,
   стоящие в колонке, выровненной по заголовку своего раздела. */
.ix-grid{display:grid;gap:26px 44px;
         grid-template-columns:repeat(auto-fill,minmax(235px,1fr))}
.ix-tile{display:block;text-decoration:none}
/* ВЕСЬ СПИСОК ЛЕЖИТ НА ШАГ НИЖЕ, А УКАЗАТЕЛЬ ПОДНИМАЕТ ОДНО */
.ix-tile .n{display:block;font:600 14px var(--ui);color:var(--text2);
            margin-bottom:4px;transform-origin:left center;
            transition:color .15s,transform .15s}
.ix-tile:hover .n{color:var(--head);transform:scale(1.035)}
.ix-tile:hover .d{color:var(--dim)}
/* ОДНА СТРОКА, ВСЕГДА. Переносящаяся подпись делает свою плитку выше соседних,
   и сетка ступенями читается как сломанный список, а не как набор равных */
.ix-tile .d{display:block;font:12.5px/1.45 var(--ui);color:var(--faint);
            white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
            transition:color .15s}
/* размер здесь акцент, поэтому попросившему покоя остаётся один свет */
@media (prefers-reduced-motion:reduce){
  .ix-tile .n{transition:color .15s}
  .ix-tile:hover .n{transform:none}
}
/* ОДИН ЗАЗОР СВЕРХУ И СНИЗУ (владелец, 24.08.2026) */
:where(body.p-index) .sec-head{margin:26px 0}
:where(body.p-index) .sec-head:first-child{margin-top:4px}
@media (max-width:1000px){
  /* НА ТЕЛЕФОНЕ КАЖДЫЙ РАЗДЕЛ - ПЛАШКА: текст, прижатый к краю экрана,
     воздуха не имеет, а один воздух оставил бы список висеть в пустоте */
  :where(body.p-index) main{padding:14px 12px 56px}
  .ix-sec{background:var(--panel);border-radius:16px;padding:16px}
  :where(body.p-index) .sec-head{margin:26px 0 10px}
  :where(body.p-index) .sec-head:first-child{margin-top:4px}
  .ix-grid{grid-template-columns:1fr;gap:18px}
  .add-row{flex-direction:column;align-items:stretch}
  .u-line{flex-wrap:wrap}
}

/* ══ ЛЕНТА НОВОСТЕЙ (news.html) ════════════════════════════════════════════
   ЛЕНТА - ЭТО ТИПОГРАФИКА, И НИЧЕГО БОЛЬШЕ: колонка чтения, воздух вместо
   линеек, заголовок на ступень выше тела */

/* голова раздела на этой странице не шире колонки чтения */
/* голова ленты как у большого сервиса: имя крупно, полстроки под ним,
   календарь на другом конце строки; воздух сверху - главным образом рост букв */
.nw-head{display:flex;align-items:flex-start;justify-content:space-between;
         gap:20px;max-width:var(--read-col);margin:8px 0 20px}
.nw-h{margin:0;font:700 26px/1.15 var(--ui);letter-spacing:-.02em;color:var(--text)}
.nw-sub{margin:5px 0 0;font:400 13px/1.45 var(--ui);color:var(--dim)}
.nw-head .hd-sw{flex:none}
@media (max-width:1000px){
  .nw-head{flex-direction:column;gap:14px;margin:4px 0 18px}
  /* в колонке кнопка дня стоит слева, и полка открывается от левого края:
     прибитая к правому, она уезжала за экран */
  .nw-head .dp-pop{left:0;right:auto}
}

/* ── ряд управления под заголовком раздела: часы и фильтр ──────────────── */
.nw-bar{display:flex;align-items:center;gap:28px;flex-wrap:wrap;
        max-width:var(--read-col);margin:0 0 8px}
/* ФИЛЬТР - ЭТО И ЛЕГЕНДА. Слово веса горит цветом своего значка в ленте, и
   контрол объясняет значки без строки пояснений */
.nw-flt{display:inline-flex;align-items:center;gap:22px}
/* ДВЕ ГРУППЫ - ДВА ВОПРОСА: вес и новизна, и они перемножаются */
.nw-grp{display:inline-flex;align-items:center;gap:11px}
.nw-flt button{border:0;background:none;cursor:pointer;padding:0;
               height:var(--ctl);font:600 11.5px var(--ui);letter-spacing:.04em;
               color:var(--faint);border-bottom:1.5px solid transparent;
               transition:color .15s,border-color .15s}
.nw-flt button:hover{color:var(--text2)}
.nw-flt button.on{color:var(--text);border-bottom-color:currentColor}
.nw-flt button.on[data-v="high"]{color:var(--down)}
.nw-flt button.on[data-v="elevated"]{color:var(--warn)}

/* ── ДЕНЬ - ЕДИНСТВЕННАЯ СТРУКТУРА ЛЕНТЫ ────────────────────────────────
   История несёт свой час, а день читатель восстанавливал бы руками. Заголовок
   тихий и мелкий - мебель, не новость, - и липкий: день, внутри которого
   читатель находится, остаётся названным при прокрутке.
   ДВА ИНТЕРВАЛА И НИЧЕГО МЕЖДУ НИМИ: шаг 24 - от истории к истории и от дня к
   его первой истории, разрыв 48 - где чтение меняется. */
.nw-dh{position:sticky;top:0;z-index:1;max-width:var(--read-col);
       margin:30px 0 0;padding:10px 0 8px;background:var(--bg);
       font:700 12px/1 var(--ui);letter-spacing:.08em;text-transform:uppercase;
       color:var(--text2)}
.nw{max-width:var(--read-col);padding:16px 0 8px}
/* пустая лента держит высоту для подвала и говорит об этом там, где стояла бы
   первая история */
#feed.loading,#feed:has(.nquiet){min-height:max(300px,calc(100vh - 420px))}
#feed .nquiet{max-width:var(--read-col)}
/* строка меты: час UTC и издание. ОДНА ГАРНИТУРА, РАЗЛИЧАЕТ ВЕС */
.nw-m{display:flex;align-items:baseline;gap:.5em;flex-wrap:wrap;
      margin:0 0 4px;font:400 13px/1.4 var(--ui);color:var(--text2)}
.nw-at{font-variant-numeric:tabular-nums}
.nw-by{font-weight:500}
/* ВЕС, КОТОРЫЙ ДАЛА МОДЕЛЬ: те же два слова, что у фильтра, и различаются тем
   же тоном */
.nw-lv{font:600 10.5px var(--ui);letter-spacing:.04em;cursor:help}
.nw-lv.high{color:var(--down)}
.nw-lv.elevated{color:var(--warn)}
.nw-nv{font:600 10.5px var(--ui);letter-spacing:.04em;color:var(--dim)}
/* заголовок И ЕСТЬ ссылка: отдельное "читать" было бы второй целью для одного
   действия. Цветом текста */
.nw-t{margin:0;font:700 18px/1.4 var(--ui)}
.nw-t a{color:var(--text);text-decoration:none}
.nw-t a:hover{text-decoration:underline;text-underline-offset:3px}
.nw-s{margin:6px 0 0;font:400 16px/1.55 var(--ui);color:var(--text2)}
/* подвал ленты: шаги пейджера и капсула размера, без плашки */
.nw-foot{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
         max-width:var(--read-col);margin-top:40px;padding:16px 0 8px;
         border-top:1px solid var(--line2)}
.nw-foot .sp{flex:1}
@media (max-width:1000px){
  .nw-bar{gap:14px}
  .nw-t{font-size:17px}
  .nw-s{font-size:15px}
}

/* ── ПЕЙДЖЕР: ДВА ШАГА И ДИАПАЗОН МЕЖДУ НИМИ ──────────────────────────────
   Контрол портала, а не страницы: страница держит только геометрию своего
   подвала. Счётчик читается как плашки сводки: живой диапазон ярко, слово и
   итог приглушены. ОДНА ГАРНИТУРА - ровность цифр даёт tabular-nums. */
.pg-btn{border:0;cursor:pointer;background:var(--panel);color:var(--dim);
        height:var(--ctl);padding:0 18px;border-radius:10px;
        font:500 12.5px var(--ui);transition:background .15s,color .15s}
.pg-btn:hover{color:var(--text)}
.pg-btn[disabled]{opacity:.4;cursor:default}
.pg-info{display:inline-flex;align-items:baseline;gap:6px;
         font-variant-numeric:tabular-nums;white-space:nowrap}
.pg-info .rng{font:600 13px var(--ui);color:var(--text2)}
.pg-info .of{font:10.5px var(--ui);color:var(--faint);
             text-transform:uppercase;letter-spacing:.14em}
.pg-info .tot{font:12.5px var(--ui);color:var(--faint)}

/* ── ДЕНЬ ВЫБИРАЕТСЯ, А НЕ НАБИРАЕТСЯ (.dp, канон портала) ──────────────
   Поле даты просит знать формат, календарь показывает, что есть. И только
   это: день, которого лента не видела, не предлагается - контрол не может
   привести на пустой экран, а точка под числом говорит, насколько день был
   занят. Разметка и поведение - UI.dayPicker в ui.js. */
.dp{position:relative;flex:none}
.dp-b{display:inline-flex;align-items:center;gap:8px;cursor:pointer;
      height:var(--ctl);padding:0 14px;border:0;border-radius:10px;
      font:500 12.5px var(--ui);color:var(--text2);background:var(--panel);
      box-shadow:var(--lift);transition:color .15s}
.card .dp-b{background:var(--panel-hi)}
.dp-b:hover{color:var(--text)}
.dp-b .cv{font-variant-numeric:tabular-nums}
.dp-b svg{width:9px;height:9px;opacity:.6;transition:transform .18s}
.dp-b[aria-expanded="true"] svg{transform:rotate(180deg)}
/* панель поднята своей бумагой и тенью, без контура */
.dp-pop{position:absolute;right:0;top:calc(100% + 8px);z-index:30;
        width:266px;padding:14px;border-radius:14px;
        background:var(--panel-hi);box-shadow:0 8px 20px rgba(0,0,0,.28)}
.dp-h{display:flex;align-items:center;justify-content:space-between;margin:0 0 10px}
.dp-h b{font:600 13px var(--ui);color:var(--text);font-variant-numeric:tabular-nums}
.dp-arw{width:26px;height:26px;display:inline-flex;align-items:center;
        justify-content:center;cursor:pointer;border:0;border-radius:8px;
        background:transparent;color:var(--dim);font:400 15px/1 var(--ui)}
.dp-arw:hover:not([disabled]){background:var(--hover);color:var(--text)}
.dp-arw[disabled]{opacity:.25;cursor:default}
/* семь колонок, и буквы дней стоят в той же сетке, что и числа */
.dp-wd,.dp-grid{display:grid;grid-template-columns:repeat(7,1fr);gap:2px}
.dp-wd{margin-bottom:4px}
.dp-wd span{text-align:center;font:600 10px/1 var(--ui);color:var(--faint);
            letter-spacing:.08em}
.dp-d{position:relative;height:32px;border:0;border-radius:9px;
      background:transparent;cursor:pointer;font:400 12.5px var(--ui);
      color:var(--text2);font-variant-numeric:tabular-nums;transition:background .12s}
.dp-d:hover:not([disabled]){background:var(--hover);color:var(--text)}
.dp-d[disabled]{color:var(--faint);opacity:.45;cursor:default}
/* ВЫБРАННЫЙ ДЕНЬ ГОРИТ КАК ВСЁ ВЫБРАННОЕ - .on, а не .sel */
.dp-d.on{background:var(--panel-top);color:var(--text);font-weight:600}
/* насколько занят день - одной точкой: её прозрачность несёт счёт против
   самого занятого дня окна */
.dp-d .dt{position:absolute;left:50%;bottom:4px;transform:translateX(-50%);
          width:3px;height:3px;border-radius:50%;background:currentColor}
.dp-all{width:100%;margin-top:10px;padding:8px;cursor:pointer;border:0;
        border-radius:9px;background:transparent;color:var(--dim);
        font:500 12px var(--ui);transition:background .12s,color .12s}
.dp-all:hover{background:var(--hover);color:var(--text)}
@media (prefers-reduced-motion:reduce){.dp-b svg{transition:none}}

/* ── КУХНЯ ШИНЫ И NOTIFY ──────────────────────────────────────────────── */
/* ключ факта - код, и он один в моно; длинный не растягивает таблицу */
.r-key{max-width:38ch;overflow:hidden;text-overflow:ellipsis}
.r-key{font:12.5px var(--mono)}
/* версии - числа в столбце: ровность даёт tabular-nums, не смена гарнитуры */
.vt td.num{font-variant-numeric:tabular-nums}
.vt b.warn{color:var(--warn)}
/* МАРШРУТ - СТРОКА СПИСКА (.u-row), а не таблица */
.r-f{font:600 12.5px var(--ui);color:var(--text)}
.r-as{margin-left:10px;font:12.5px var(--ui);color:var(--dim)}
.u-row.off .u-main{opacity:.55}
/* ряд заведения стоит ПОД списком, внутри карточки */
/* РЯД ЗАВЕДЕНИЯ - ТАКАЯ ЖЕ СТРОКА СПИСКА: тот же боковой отступ, те же 13
   сверху и снизу, та же линейка перед ним */
.r-add{padding:13px var(--pad);margin-top:0;border-top:1px solid var(--line2)}
.r-add .tb-count:empty{display:none}
/* ОТКАЗ - СВОЕЙ СТРОКОЙ ПОД РЯДОМ, а не в строке после кнопки: в строке он
   отжимал поля и двигал весь ряд вправо. Цветом - потому что это беда. */
.r-add .tb-count{flex-basis:100%;order:9;margin-top:2px;color:var(--warn)}
.r-in{flex:1 1 160px}
/* ПОЛЕ И СТРЕЛКА - ОДИН КОНТРОЛ, КАК У КОМБОБОКСА */
.r-fw{position:relative;display:flex;gap:8px;flex:1 1 160px;min-width:0}
.r-fw .r-in{flex:1;min-width:0}
.r-fw .sel{position:static}
.r-fw .sel-sheet{left:0;right:0;min-width:0;transform-origin:top left}
@media (max-width:1000px){
  /* В КОЛОНКЕ flex-basis МЕРИТ ВЫСОТУ: поле шириной 160 становилось полем
     высотой 160. Базис снимается, высоту держит закон ряда (--ctl). */
  .r-add{flex-direction:column;align-items:stretch}
  .r-add .r-in,.r-add .r-fw{flex:none}
  /* ДЕЙСТВИЯ УХОДЯТ ПОД ТЕКСТ, а не зажимают его сбоку */
  .u-act{flex-basis:100%}
}

/* ══ ВИЗИТКА API (web/api/index.html): страница текста без меню ═══════════
   В прозе кода нет - строки не скачут. Ручка, как в справочниках Stripe и
   GitHub: адрес строкой (моно), описание строкой, параметры колонкой: имя в
   моно своей колонкой, описание прозой, у обеих одна высота строки. */
:where(body.p-api) main{max-width:var(--read-col);padding-top:14px;padding-bottom:120px}
:where(body.p-api) .doc h2{margin:48px 0 14px;font:700 22px/1.25 var(--ui);
                            letter-spacing:-.01em;color:var(--head)}
:where(body.p-api) .doc h2:first-child{margin-top:12px}
:where(body.p-api) .doc p{margin:0 0 14px;font:400 15px/1.65 var(--ui);color:var(--text2)}
:where(body.p-api) .doc pre{margin:14px 0 18px;padding:16px 18px;border-radius:14px;
                            background:var(--panel);font:500 13px/1.7 var(--mono);
                            color:var(--text);overflow-x:auto}
:where(body.p-api) .ep{margin:0 0 26px}
:where(body.p-api) .ep-path{display:block;margin:0 0 4px;font:500 14px/1.6 var(--mono);color:var(--text)}
:where(body.p-api) .ep .doc-p,:where(body.p-api) .ep p{margin:0 0 10px}
:where(body.p-api) .args{display:grid;grid-template-columns:max-content 1fr;gap:2px 22px;
                         margin:0;font:400 14.5px/23px var(--ui);color:var(--text2)}
:where(body.p-api) .args dt{margin:0;font:500 13px/23px var(--mono);color:var(--text)}
:where(body.p-api) .args dd{margin:0}
@media (max-width:1000px){
  :where(body.p-api) main{padding-bottom:80px}
  :where(body.p-api) .doc h2{margin-top:36px}
  :where(body.p-api) .args{grid-template-columns:1fr;gap:0}
  :where(body.p-api) .args dt{margin-top:8px}
}
/* новый токен на кухне: секрет показан один раз, копия под рукой */
.tk-new{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
        padding:13px var(--pad);border-top:1px solid var(--line)}
.tk-new code{font:500 12.5px var(--mono);color:var(--text);word-break:break-all}
