/*
 * MyBeast id - one stylesheet, no build step. The numbers are the Asuvaan design book's
 * (AsuvaanV2/design-system/ui/src/styles/tokens.css): one neutral hue, one accent, night for the primary button,
 * a state is a glyph and a word, cards are a hairline. Light and dark from the same lines (light-dark()).
 */

@font-face { font-family: 'Inter'; font-weight: 400; font-display: swap; src: url('../fonts/inter-latin-400-normal.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-weight: 500; font-display: swap; src: url('../fonts/inter-latin-500-normal.woff2') format('woff2'); }
@font-face { font-family: 'Inter'; font-weight: 600; font-display: swap; src: url('../fonts/inter-latin-600-normal.woff2') format('woff2'); }
@font-face { font-family: 'JetBrains Mono'; font-weight: 400; font-display: swap; src: url('../fonts/jetbrains-mono-latin-400-normal.woff2') format('woff2'); }

:root {
    color-scheme: light dark;
    --hue: 255;
    --accent-hue: 262;

    /* The tones, back to front (29.10.2026): the frame - the top bar and the sidebar - is the darkest, the canvas the pages
       lie on a step lighter, the sheets on it (cards, tiles, panels, tables) a step lighter again, a menu over them and a
       dialog over everything lighter still. Nearer is lighter, in both modes: in light mode the frame is a cool grey and
       the sheets are the only pure white; in dark mode the frame is near black and each step up is a little more light.
       The frame carries a little of the hue so it reads as made, not as disabled. */
    --chrome: light-dark(oklch(95.4% 0.009 var(--hue)), oklch(13.5% 0.03 var(--hue)));
    --chrome-2: light-dark(oklch(92.2% 0.012 var(--hue)), oklch(19% 0.032 var(--hue)));
    --canvas: light-dark(oklch(97.7% 0.005 var(--hue)), oklch(18% 0.024 var(--hue)));
    --surface: light-dark(oklch(100% 0 0), oklch(22.5% 0.027 var(--hue)));
    --surface-2: light-dark(oklch(96.4% 0.007 var(--hue)), oklch(26.5% 0.029 var(--hue)));
    --raised: light-dark(oklch(100% 0 0), oklch(26.5% 0.029 var(--hue)));
    --overlay: light-dark(oklch(100% 0 0), oklch(29% 0.029 var(--hue)));
    /* The lines: the frame's edge against the canvas, a sheet's edge and the rows inside it, the stronger one of buttons
       and badges, and the one a box must be seen by. */
    --line-chrome: light-dark(oklch(88.5% 0.014 var(--hue)), oklch(25.5% 0.032 var(--hue)));
    --line: light-dark(oklch(91.2% 0.009 var(--hue)), oklch(31% 0.03 var(--hue)));
    --line-2: light-dark(oklch(86% 0.012 var(--hue)), oklch(38.5% 0.032 var(--hue)));
    --line-control: light-dark(oklch(63% 0.02 var(--hue)), oklch(58% 0.03 var(--hue)));
    --ink: light-dark(oklch(21% 0.035 var(--hue)), oklch(96% 0.008 var(--hue)));
    --ink-2: light-dark(oklch(40% 0.03 var(--hue)), oklch(80% 0.02 var(--hue)));
    --ink-3: light-dark(oklch(50% 0.025 var(--hue)), oklch(70% 0.022 var(--hue)));

    --night: #0a2540;
    --moon: #f2eedf;
    --primary: light-dark(var(--night), var(--moon));
    --on-primary: light-dark(var(--moon), var(--night));
    --primary-hover: light-dark(oklch(36% 0.08 var(--hue)), #ffffff);

    --accent: light-dark(oklch(52% 0.2 var(--accent-hue)), oklch(74% 0.13 var(--accent-hue)));
    --accent-ink: light-dark(oklch(42% 0.17 var(--accent-hue)), oklch(82% 0.1 var(--accent-hue)));
    --accent-wash: light-dark(oklch(95.5% 0.025 var(--accent-hue)), oklch(26% 0.06 var(--accent-hue)));

    --pos-ink: light-dark(oklch(41% 0.1 150), oklch(80% 0.13 150));
    --pos-wash: light-dark(oklch(96% 0.035 150), oklch(26% 0.05 150));
    --pos-edge: light-dark(oklch(87% 0.07 150), oklch(36% 0.07 150));
    --caut-ink: light-dark(oklch(42% 0.09 70), oklch(84% 0.12 85));
    --caut-wash: light-dark(oklch(96.5% 0.05 90), oklch(27% 0.05 80));
    --caut-edge: light-dark(oklch(87% 0.09 88), oklch(38% 0.07 80));
    --neg-ink: light-dark(oklch(45% 0.18 25), oklch(80% 0.12 22));
    --neg-wash: light-dark(oklch(96% 0.025 20), oklch(26% 0.06 22));
    --neg-edge: light-dark(oklch(72% 0.13 22), oklch(56% 0.13 22));
    --neg: light-dark(oklch(50% 0.2 27), oklch(66% 0.19 25));

    --plate: linear-gradient(112deg, #0a2540 0%, #0a2540 48%, #0c2b4e 76%, #10365f 100%);
    --plate-ink: #ffffff;
    --plate-ink-2: oklch(86% 0.02 250);

    --font: 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
    --mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;
    --fs-caption: 0.8125rem;
    --fs-body: 0.875rem;
    --fs-lead: 1rem;
    --fs-title: 1.25rem;
    --fs-display: 1.75rem;
    --s-1: 4px; --s-2: 8px; --s-3: 12px; --s-4: 16px; --s-5: 24px; --s-6: 32px; --s-7: 48px;
    --r-control: 10px;
    --r-surface: 14px;
    --h-control: 40px;
    --h-sm: 32px;
    --h-top: 52px;
    /* The shadows, by step: a sheet on the canvas has the faintest, a menu a soft one, a dialog the widest. light-dark()
       takes a colour only, so the shade is the token and the shadow is built from it. In dark mode a shadow hardly shows
       against a dark canvas, so there the step in tone and the line do the work and the shade is only a seam. */
    --shade-1: light-dark(oklch(25% 0.03 var(--hue) / 0.06), oklch(0% 0 0 / 0.4));
    --shade-2: light-dark(oklch(25% 0.03 var(--hue) / 0.12), oklch(0% 0 0 / 0.5));
    --shade-3: light-dark(oklch(25% 0.03 var(--hue) / 0.18), oklch(0% 0 0 / 0.6));
    --shadow-card: 0 1px 2px var(--shade-1);
    --shadow-raised: 0 8px 24px var(--shade-2), 0 1px 2px var(--shade-1);
    --shadow-float: 0 12px 32px var(--shade-3);
}
/* The look a person chose (Preferences, <html data-theme>): one scheme whatever the device says, every token above
   following it through light-dark(); nothing said follows the device. */
:root[data-theme='light'] { color-scheme: light; }
:root[data-theme='dark'] { color-scheme: dark; }

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
    margin: 0;
    background: var(--chrome);
    color: var(--ink);
    font: 400 var(--fs-body)/1.5 var(--font);
    overflow-wrap: break-word;
}
a { color: var(--accent-ink); text-underline-offset: 2px; cursor: pointer; }
a:hover { color: var(--accent); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
h1, h2, h3 { margin: 0; font-weight: 600; letter-spacing: -0.01em; }
h1 { font-size: var(--fs-display); line-height: 1.2; }
h2 { font-size: var(--fs-title); line-height: 1.3; }
h3 { font-size: var(--fs-lead); }
p { margin: 0; }
code, .mono { font-family: var(--mono); font-size: 0.92em; }
.muted { color: var(--ink-3); }
.small { font-size: var(--fs-caption); }
.stack > * + * { margin-top: var(--s-4); }
.stack-lg > * + * { margin-top: var(--s-6); }
.row { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; }
.row-between { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); flex-wrap: wrap; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

/* ── The shell (29.10.2026): one top bar and one sidebar in every MyBeast app. This block is the same text in id's and
   services' app.css - change it in one, copy it to the other (Status and Auth carry the shell too). Three tones, back
   to front: the frame - the top bar and the sidebar, one L with no line between them - is the darkest, the canvas the
   pages lie on a step lighter, set into the frame with a rounded corner where the bar and the sidebar meet, and the
   sheets on it (cards, tiles, panels, tables) the lightest, each with a hairline and the faintest shadow. ── */

/* The top bar says where you are on the left and what you can do anywhere on the right. Left: the mark (MyBeast, a link
   to every product), then the hierarchy as three doors with a slash between them - the workspace (components/
   workspace-switcher), the project you work in (components/project-switcher), the product you are in, with its icon
   (components/switcher) -, each a menu of its peers that ends in the way to its settings. Right: the environment when
   it is not production, search (⌘K, components/palette), your account (components/account: who you are, Account and
   security, Sign out). An app's sections are never here: they are the sidebar's, so the bar is the same bar in every
   app. It stays at the top while the page scrolls. */
.top { position: sticky; top: 0; z-index: 31; display: flex; align-items: center; gap: var(--s-1); height: var(--h-top); padding: 0 var(--s-4) 0 var(--s-3); background: var(--chrome); }
.top-mark { display: grid; place-items: center; flex: none; width: 36px; height: 36px; margin-right: 2px; border-radius: var(--r-control); color: var(--primary); text-decoration: none; }
.top-mark:hover { background: var(--chrome-2); color: var(--primary); }
.top-mark svg { width: 22px; height: 22px; }
.top-mark .mark-dot { fill: var(--on-primary); }
/* A door is a <summary>: its menu opens without a script and closes on a click outside, Escape or Tab (app.js). Quiet on
   the chrome, a tone darker under the pointer, lifted to the sheet's white while its menu is open. */
.top-menu { position: relative; min-width: 0; flex: 0 1 auto; }
.top-door { list-style: none; display: flex; align-items: center; gap: 5px; height: 32px; padding: 0 6px 0 10px; border-radius: 8px; color: var(--ink); font-weight: 600; white-space: nowrap; cursor: pointer; }
.top-door::-webkit-details-marker { display: none; }
.top-door:hover { background: var(--chrome-2); }
.top-menu[open] > .top-door { background: var(--surface); box-shadow: 0 0 0 1px var(--line-chrome), var(--shadow-card); }
.top-door-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.top-door .top-chevron { flex: none; width: 14px; height: 14px; color: var(--ink-3); transition: transform 0.12s; }
.top-menu[open] > .top-door .top-chevron { transform: rotate(180deg); }
/* The product's door carries its icon (components/product-icon); the suite's, at id and on a page of every product, none.
   The workspace's and the project's doors (.top-context) are lighter and cut at 260 px, so three doors and the search fit.
   A door with nothing to be in - no project chosen, no product on a page of every product or at id - is muted and reads
   what it is ("Choose a project", "Product"). */
.top-door .product-icon { flex: none; width: 18px; height: 18px; margin: 0 2px 0 -2px; color: var(--ink-2); }
.top-context .top-door { max-width: 260px; font-weight: 500; }
.top-door.is-none { color: var(--ink-3); font-weight: 500; }
.top-sep { flex: none; padding: 0 3px; color: var(--line-control); font-size: 18px; font-weight: 300; line-height: 1; user-select: none; }
.top-actions { display: flex; align-items: center; gap: var(--s-2); flex: none; margin-left: auto; padding-left: var(--s-3); }
/* Outside production a pill says so: a dot and the word, never the colour alone. */
.top-env { display: inline-flex; align-items: center; gap: 5px; height: 24px; padding: 0 9px 0 8px; border: 1px solid var(--caut-edge); border-radius: 999px; background: var(--caut-wash); color: var(--caut-ink); font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; white-space: nowrap; }
.top-env .glyph { width: 7px; height: 7px; }
/* Search: the ⌘K palette's door (palette.css draws the dialog) - a white box on the chrome, the one thing in the bar that
   looks like a field, because it is one. Its key is shown as a key. */
.top-search { display: inline-flex; align-items: center; gap: var(--s-2); flex: none; width: 220px; height: 32px; padding: 0 5px 0 10px; border: 1px solid var(--line-chrome); border-radius: 8px; background: var(--surface); color: var(--ink-3); font: inherit; font-size: var(--fs-caption); text-decoration: none; cursor: pointer; box-shadow: var(--shadow-card); }
.top-search:hover { border-color: var(--line-2); color: var(--ink-2); }
.top-search .glyph { width: 14px; height: 14px; }
.top-search-text { flex: 1; text-align: left; }
.top-key { display: inline-block; min-width: 20px; padding: 3px 5px; border: 1px solid var(--line); border-bottom-width: 2px; border-radius: 5px; background: var(--surface-2); color: var(--ink-3); font: 500 11px/1 var(--font); text-align: center; white-space: nowrap; }
/* The account's door: who is signed in as a letter in a disc. */
.top-account > .top-door { width: 36px; padding: 0; justify-content: center; }
.avatar { display: grid; place-items: center; flex: none; width: 28px; height: 28px; border-radius: 50%; background: var(--primary); color: var(--on-primary); font-size: 12px; font-weight: 600; letter-spacing: 0.02em; line-height: 1; text-transform: uppercase; }

/* A menu hangs under its door, raised over the page: a hairline, rows of 36 px with an icon, a name and a line under it,
   the one you are at ticked and heavier. The product, the project (or workspace) and the account menus share it. */
.menu { position: absolute; top: calc(100% + 6px); left: 0; z-index: 30; display: flex; flex-direction: column; gap: 1px; min-width: 240px; max-height: calc(100vh - 80px); overflow-y: auto; padding: var(--s-2); background: var(--raised); border: 1px solid var(--line); border-radius: var(--r-surface); box-shadow: var(--shadow-raised); }
.menu-end { left: auto; right: 0; }
.menu-head, .switcher-group-name { padding: 8px 10px 4px; color: var(--ink-3); font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; }
.menu-item { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 36px; padding: 6px 10px; border: 0; border-radius: var(--r-control); background: none; color: var(--ink); font: inherit; text-align: left; text-decoration: none; cursor: pointer; }
.menu-item:hover, .menu-item:focus-visible { background: var(--surface-2); color: var(--ink); }
.menu-item:focus-visible { outline-offset: -2px; }
.menu-item[aria-current] { font-weight: 600; }
.menu-icon { display: grid; place-items: center; flex: none; width: 30px; height: 30px; border-radius: 8px; background: var(--surface-2); color: var(--ink-2); }
.menu-item:hover .menu-icon { background: var(--raised); color: var(--accent-ink); box-shadow: 0 0 0 1px var(--line); }
.menu-item[aria-current] .menu-icon { background: var(--accent-wash); color: var(--accent-ink); box-shadow: none; }
.menu-icon .product-icon, .menu-icon .nav-icon { width: 17px; height: 17px; }
.menu-text { display: flex; flex: 1; flex-direction: column; gap: 1px; min-width: 0; }
.menu-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; }
.menu-item[aria-current] .menu-name { font-weight: 600; }
.menu-about { color: var(--ink-3); font-size: var(--fs-caption); line-height: 1.35; font-weight: 400; }
.menu-check { flex: none; width: 16px; height: 16px; margin-left: auto; color: var(--accent-ink); }
.menu-foot { display: flex; flex-direction: column; gap: 1px; margin-top: var(--s-2); padding-top: var(--s-2); border-top: 1px solid var(--line); }
.menu-foot .menu-item { min-height: 32px; color: var(--accent-ink); font-weight: 500; }
.menu-foot .menu-item[aria-current] { color: var(--ink); font-weight: 600; }
.menu-item > .nav-icon { flex: none; width: 16px; height: 16px; color: var(--ink-3); }
.menu-item:hover > .nav-icon, .menu-item[aria-current] > .nav-icon { color: var(--ink-2); }
/* Products (components/switcher): every product in its group, two columns of groups - one on a phone, or with one
   group -, each with its icon and a line about it (cut short: the whole is on id's home); under them the places that
   are every product's. */
.menu-products { width: min(700px, calc(100vw - 32px)); padding: var(--s-3); }
.switcher-groups { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-4) var(--s-3); }
.switcher-group { display: flex; flex-direction: column; gap: 1px; }
.menu-products .menu-about { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.menu-products .menu-foot { flex-direction: row; flex-wrap: wrap; gap: 2px var(--s-2); }
.menu-products .menu-foot .menu-item { width: auto; }
.menu-products:not(:has(.switcher-group + .switcher-group)) { width: min(340px, calc(100vw - 32px)); }
.menu-products:not(:has(.switcher-group + .switcher-group)) .switcher-groups { grid-template-columns: minmax(0, 1fr); }
/* What the project has not added (29.10.2026): under the groups, muted - an outlined tile, the name in the quiet ink -,
   "Not added to …" said above them; for its workspace's owners each leads to the Subscription page, "Add ↗". */
.switcher-off { margin-top: var(--s-3); padding-top: var(--s-2); border-top: 1px solid var(--line); }
.switcher-off-items { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1px var(--s-2); }
.menu-item.is-off { min-height: 32px; color: var(--ink-3); }
.menu-item.is-off .menu-icon, span.menu-item.is-off:hover .menu-icon { width: 24px; height: 24px; background: none; box-shadow: inset 0 0 0 1px var(--line); color: var(--ink-3); }
.menu-item.is-off .menu-name { font-weight: 400; }
a.menu-item.is-off:hover { color: var(--ink-2); }
span.menu-item.is-off { cursor: default; }
span.menu-item.is-off:hover { background: none; color: var(--ink-3); }
.menu-add { flex: none; margin-left: auto; color: var(--accent-ink); font-size: var(--fs-caption); font-weight: 500; }
@media (max-width: 720px) { .switcher-groups { grid-template-columns: minmax(0, 1fr); } }
/* Workspaces and projects (components/workspace-switcher, project-switcher): each one with its slug, the one you are in
   ticked, then under a line the way to a new one and, last, to its settings. */
.menu-context { width: min(320px, calc(100vw - 32px)); }
.menu-slug { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ink-3); font-family: var(--mono); font-size: var(--fs-caption); }
.menu-empty { padding: 8px 10px; color: var(--ink-3); font-size: var(--fs-caption); }
/* The account: who is signed in, the account's places, then Sign out - a form's button drawn as a row of the menu. */
.menu-account { width: min(280px, calc(100vw - 32px)); }
.menu-who { display: flex; align-items: center; gap: 10px; margin-bottom: var(--s-2); padding: 6px 10px 10px; border-bottom: 1px solid var(--line); }
.menu-who .menu-name, .menu-who .menu-about { white-space: normal; overflow-wrap: anywhere; }
.menu-account form { display: contents; }

/* The brand on a guest page (sign-in, two-factor): the mark and the name, nothing to switch. */
.brand { display: flex; align-items: center; gap: var(--s-2); color: var(--ink); font-weight: 600; text-decoration: none; }
.brand:hover { color: var(--ink); }
.brand-mark { width: 12px; height: 12px; border-radius: 50%; background: var(--primary); box-shadow: 0 0 0 3px var(--surface), 0 0 0 4px var(--line-2); margin: 0 4px; }
.env { font-size: 11px; font-weight: 600; letter-spacing: 0.06em; color: var(--caut-ink); background: var(--caut-wash); border: 1px solid var(--caut-edge); border-radius: 999px; padding: 1px 8px; }

/* The sidebar (components/sidebar): an app's sections - id's Products, Workspaces …; a module's places - on the frame's
   tone under the bar with no line of its own, the page beside it on the canvas. The place of this page is lifted to the
   sheet's white, with the sheet's edge, the bar at the sidebar's edge, the weight, its icon in the accent and
   aria-current: never a colour alone. */
.shell { display: grid; grid-template-columns: minmax(0, 1fr); min-height: calc(100vh - var(--h-top)); background: var(--chrome); }
.shell.has-side { grid-template-columns: 232px minmax(0, 1fr); }
.side { min-width: 0; }
.side-nav { position: sticky; top: var(--h-top); display: flex; flex-direction: column; gap: 2px; max-height: calc(100vh - var(--h-top)); overflow-y: auto; padding: var(--s-3) var(--s-3) var(--s-5); scrollbar-width: thin; }
.side-group { display: flex; flex-direction: column; gap: 2px; margin-top: var(--s-5); }
.side-group:first-child { margin-top: 0; }
.side-head { padding: 0 10px var(--s-1); color: var(--ink-3); font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; }
.side-link { position: relative; display: flex; align-items: center; gap: 10px; min-height: 34px; padding: 5px 10px; border-radius: 8px; color: var(--ink-2); font-weight: 500; text-decoration: none; }
.side-link:hover { background: var(--chrome-2); color: var(--ink); }
.side-link .nav-icon { width: 18px; height: 18px; flex: none; color: var(--ink-3); }
.side-link:hover .nav-icon { color: var(--ink-2); }
.side-link[aria-current] { background: var(--surface); color: var(--ink); font-weight: 600; box-shadow: 0 0 0 1px var(--line-chrome), var(--shadow-card); }
.side-link[aria-current] .nav-icon { color: var(--accent-ink); }
.side-link[aria-current]::before { content: ''; position: absolute; top: 7px; bottom: 7px; left: calc(-1 * var(--s-3)); width: 3px; border-radius: 0 3px 3px 0; background: var(--primary); }

/* The project menu (components/sidebar with `sub`, 29.10.2026): on a project's page of Settings - at id and at services
   the same - a column of the page beside its content, on the canvas; the sidebar stays as it is. Its page's place is
   lifted as the sidebar's is, the bar at the column's edge. The column is as tall as the page, so the menu stays in view
   under the bar while the page scrolls, as the sidebar does; a section a link opens (#people) stops below the bar. So
   does a control the keyboard focuses, and below a page's own bar under the top bar too (Errors' issue, a stuck point):
   that page's sheet sets --h-bar on the root to the bar's height, since Firefox scrolls focus only just into view. */
html { scroll-padding-top: calc(var(--h-top) + var(--h-bar, 0px) + var(--s-4)); }
.page.has-sub { display: grid; grid-template-columns: 200px minmax(0, 1fr); gap: var(--s-6); }
.page-body { min-width: 0; }
.sub { min-width: 0; }
.sub .side-nav { top: calc(var(--h-top) + var(--s-5)); max-height: calc(100vh - var(--h-top) - var(--s-5) - var(--s-7)); padding: 0 0 0 var(--s-2); }
.sub .side-link:hover { background: var(--chrome); }
.sub .side-link[aria-current]::before { left: calc(-1 * var(--s-2)); }

/* The page: on the canvas, set into the frame - a hairline above and, beside a sidebar, on the left, the corner rounded
   where the bar and the sidebar meet - and as wide as the window leaves it. */
.page { min-width: 0; padding: var(--s-5) var(--s-6) var(--s-7); background: var(--canvas); border-top: 1px solid var(--line-chrome); }
.shell.has-side > .page { border-left: 1px solid var(--line-chrome); border-top-left-radius: 12px; }
.page-head { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--s-4); flex-wrap: wrap; margin-bottom: var(--s-5); }
.page-head .sub { color: var(--ink-3); margin-top: var(--s-1); }
/* A page's heading that is read out only (projects/_plate at services): nothing above the page's own head. */
.page > h1.sr-only + *, .page-body > h1.sr-only + * { margin-top: 0; }

/* Narrower than 1100: the search is its glyph and its key; a long name is cut sooner. */
@media (max-width: 1100px) {
    .top-search { width: auto; }
    .top-search-text { display: none; }
    .top-context .top-door { max-width: 200px; }
}
/* Narrower than 900: the sidebar's places are a row under the bar that scrolls sideways, on the frame's tone still, the
   page's own underlined (app.js brings it into view); the canvas starts under the row, square. */
@media (max-width: 900px) {
    .top { padding: 0 var(--s-3); }
    .shell.has-side { display: block; min-height: 0; }
    .side-nav { position: static; flex-direction: row; align-items: center; gap: var(--s-1); max-height: none; overflow-x: auto; scrollbar-width: none; padding: 0 var(--s-3) var(--s-2); }
    .side-group { flex-direction: row; align-items: center; gap: var(--s-1); margin: 0 0 0 var(--s-2); padding-left: var(--s-3); border-left: 1px solid var(--line-chrome); }
    .side-group:first-child { margin-left: 0; padding-left: 0; border-left: 0; }
    .side-head { display: none; }
    .side-link { flex: none; min-height: 32px; white-space: nowrap; }
    .side-link[aria-current] { background: var(--chrome-2); box-shadow: none; }
    .side-link[aria-current]::before { top: auto; right: 10px; bottom: calc(-1 * var(--s-2)); left: 10px; width: auto; height: 3px; border-radius: 3px 3px 0 0; }
    .shell.has-side > .page { border-left: 0; border-radius: 0; }
    .page { padding-inline: var(--s-5); }
    .page.has-sub { display: block; }
    aside.sub { margin-bottom: var(--s-5); border-bottom: 1px solid var(--line); }
    .sub .side-nav { padding: 0 0 var(--s-2); }
    .sub .side-link[aria-current] { background: var(--chrome); }
}
/* On a phone: the bar scrolls with the page, the mark and the doors tighter, the search a square, the product's door its
   icon alone - the workspace's and the project's names share the room -, and every menu hangs from the bar's own edge,
   so it fits the screen however long a name is. */
@media (max-width: 640px) {
    .top { position: relative; gap: 2px; padding: 0 var(--s-2); }
    .top-mark { width: 32px; height: 32px; margin-right: 0; }
    .top-menu { position: static; }
    .top-door { padding: 0 4px 0 8px; }
    .top-context .top-door { max-width: none; }
    .top-product .top-door .product-icon + .top-door-text { display: none; }
    .top-product .top-door .product-icon { margin: 0; }
    .top-actions { gap: var(--s-1); padding-left: var(--s-2); }
    .top-env { padding: 0 7px 0 6px; letter-spacing: 0.04em; }
    .top-search { width: 32px; padding: 0; justify-content: center; }
    .top-search .top-key { display: none; }
    .top-account > .top-door { width: 32px; }
    .menu { top: calc(100% + 2px); left: var(--s-2); }
    .menu-end { left: auto; right: var(--s-2); }
    .menu-products { padding: var(--s-2); }
    .page { padding: var(--s-5) var(--s-4) var(--s-6); }
}
/* A narrow phone's doors: the product's (its icon alone) keeps its size, and a door cuts its own name rather than run
   under the next one; at 480 px and less the slashes go and the workspace is its letter - its name read out only -, so
   the project's name has the room. */
@media (max-width: 640px) {
    .top-product { flex-shrink: 0; }
    .top-context > .top-door { overflow: hidden; }
}
@media (max-width: 480px) {
    .top-sep { display: none; }
    .top-workspace { flex-shrink: 0; }
    .top-workspace .top-door-text { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
}
/* The first stop of every page (the layout's skip link), straight past the bar and the sidebar: seen only while it has
   focus. --accent-ink on --surface is 8.8:1 in light, 9.8:1 in dark. */
.skip-link { position: absolute; top: var(--s-2); left: var(--s-3); z-index: 40; padding: 8px 12px; border-radius: var(--r-control); background: var(--surface); color: var(--accent-ink); font-weight: 600; box-shadow: var(--shadow-raised); transform: translateY(-150%); }
.skip-link:focus { transform: none; }
main[tabindex='-1']:focus { outline: none; }
@media print {
    .top, .side, aside.sub { display: none; }
    .shell, .shell.has-side, .page.has-sub { display: block; min-height: 0; }
    .page { border: 0; }
}

/* The plate: one per page, the project's head. */
.plate { background: var(--plate); color: var(--plate-ink); border-radius: var(--r-surface); padding: var(--s-5) var(--s-5) 0; margin-bottom: var(--s-5); }
.plate .sub { color: var(--plate-ink-2); margin-top: var(--s-1); }
.plate .tabs { display: flex; gap: var(--s-1); margin-top: var(--s-5); overflow-x: auto; scrollbar-width: none; }
.plate .tabs a { white-space: nowrap; }
.plate .tabs a { color: var(--plate-ink-2); text-decoration: none; padding: 10px 12px; border-bottom: 2px solid transparent; }
.plate .tabs a:hover { color: var(--plate-ink); }
.plate .tabs a[aria-current='page'] { color: var(--plate-ink); border-bottom-color: var(--plate-ink); }

/* ── Cards, tables ────────────────────────────────────────────────────── */
/* A sheet on the canvas (29.10.2026): a tone lighter, a hairline, the faintest shadow. */
.card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-surface); padding: var(--s-5); box-shadow: var(--shadow-card); }
.card-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); margin-bottom: var(--s-4); flex-wrap: wrap; }
.card-head > div { min-width: 0; }
.card-head p { color: var(--ink-3); margin-top: 2px; }
.card.flush { padding: 0; overflow: hidden; }
.card.flush .card-head { padding: var(--s-4) var(--s-5) 0; }

/* Positioned, so a visually hidden header inside scrolls with the table instead of widening the page. */
.table-wrap { overflow-x: auto; position: relative; }
table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 10px var(--s-5); border-top: 1px solid var(--line); vertical-align: middle; }
th { font-weight: 500; color: var(--ink-3); font-size: var(--fs-caption); border-top: 0; }
tbody tr:hover { background: var(--surface-2); }
td.actions { text-align: right; white-space: nowrap; }
td.actions form { display: inline; }
tr.off td { color: var(--ink-3); }

.list { list-style: none; margin: 0; padding: 0; }
.list li { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); padding: 10px 0; border-top: 1px solid var(--line); }
.list li:first-child { border-top: 0; }

.empty { color: var(--ink-3); padding: var(--s-5); text-align: center; }

/* ── Forms ────────────────────────────────────────────────────────────── */
.field { display: grid; grid-template-columns: minmax(0, 1fr); gap: 6px; align-content: start; }
.field label, .field .label { font-weight: 500; }
/* "(optional)" after a label, quieter than it: what is asked is plain, what may be left is marked. */
.field .optional { color: var(--ink-3); font-weight: 400; }
.field .hint { color: var(--ink-3); font-size: var(--fs-caption); overflow-wrap: anywhere; }
.field .error { color: var(--neg-ink); font-size: var(--fs-caption); display: flex; gap: 6px; align-items: center; overflow-wrap: anywhere; }
/* A form's fields stop at a width a line can be read at, however wide the page (29.10.2026, as services'): its card goes on. */
.fields { display: grid; gap: var(--s-4); grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); align-items: start; max-width: 60rem; }
/* Fields side by side line up: each takes three rows (label, box, the line under it) shared with the fields beside it,
   so a label that wraps moves every box in that row down together. */
.fields > * { grid-row: span 3; }
.fields > .field { grid-template-rows: subgrid; row-gap: 6px; }
/* A field that says something as it is typed (a new workspace's name and address): the note between it and its hint. */
.fields > .field:has(> .field-note) { grid-row: span 4; }
input[type='text'], input[type='email'], input[type='password'], input[type='number'], input[type='url'], input[type='search'], input[type='tel'], input[type='date'], input[type='time'], input[type='datetime-local'], select {
    font: inherit; color: var(--ink); background: var(--surface);
    height: var(--h-control); padding: 0 12px; width: 100%;
    border: 1px solid var(--line-control); border-radius: var(--r-control);
}
/* A select draws its own chevron: the browser's sits against the right edge whatever the padding. */
select {
    appearance: none; -webkit-appearance: none; cursor: pointer;
    padding-right: 36px; text-overflow: ellipsis;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%235a6472' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4 6 4 4 4-4'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right 12px center; background-size: 16px 16px;
}
@media (prefers-color-scheme: dark) {
    select { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23959fac' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4 6 4 4 4-4'/%3E%3C/svg%3E"); }
}
/* The chevron follows the look a person chose, not the device (Preferences). */
:root[data-theme='light'] select { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%235a6472' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4 6 4 4 4-4'/%3E%3C/svg%3E"); }
:root[data-theme='dark'] select { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%23959fac' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4 6 4 4 4-4'/%3E%3C/svg%3E"); }
input.mono { font-family: var(--mono); letter-spacing: 0.04em; }
input:focus-visible, select:focus-visible { outline: 2px solid var(--accent); outline-offset: 0; border-color: var(--accent); }
input[aria-invalid='true'], select[aria-invalid='true'], textarea[aria-invalid='true'] { border-color: var(--neg-edge); }
input:disabled, select:disabled, textarea:disabled { background-color: var(--surface-2); color: var(--ink-3); cursor: not-allowed; }
::placeholder { color: var(--ink-3); opacity: 1; }
.check { display: flex; width: fit-content; gap: var(--s-2); align-items: center; cursor: pointer; }
.inline-form .check { display: inline-flex; }
.check input { width: 16px; height: 16px; margin: 0; accent-color: var(--primary); }
.form-actions { display: flex; gap: var(--s-3); align-items: center; margin-top: var(--s-5); flex-wrap: wrap; }
/* It may shrink to its box: a select as wide as its longest option then narrows instead of pushing past the card's edge. */
.inline-form { display: flex; gap: var(--s-2); align-items: center; flex-wrap: wrap; min-width: 0; max-width: 100%; }
.inline-form select { width: auto; max-width: 100%; height: var(--h-sm); padding: 0 32px 0 10px; background-position: right 10px center; }

/* ── Buttons ──────────────────────────────────────────────────────────── */
.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: var(--s-2);
    height: var(--h-control); padding: 0 var(--s-4);
    font: 500 var(--fs-body)/1 var(--font); text-decoration: none; white-space: nowrap;
    border-radius: var(--r-control); border: 1px solid var(--line-2);
    background: var(--surface); color: var(--ink); cursor: pointer;
}
.btn:hover { background: var(--surface-2); color: var(--ink); }
.btn-primary { background: var(--primary); color: var(--on-primary); border-color: transparent; }
.btn-primary:hover { background: var(--primary-hover); color: var(--on-primary); }
.btn-danger { color: var(--neg-ink); }
.btn-danger:hover { background: var(--neg-wash); color: var(--neg-ink); border-color: var(--neg-edge); }
.btn-sm { height: var(--h-sm); padding: 0 var(--s-3); font-size: var(--fs-caption); }
.btn-link { background: none; border: 0; padding: 0; height: auto; color: var(--accent-ink); font-weight: 400; }
.btn-link:hover { background: none; color: var(--accent); text-decoration: underline; }
/* A button that cannot be pressed now looks it, and does not answer the pointer. */
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn:disabled:hover { background: var(--surface); }
.btn-primary:disabled:hover { background: var(--primary); }
/* On touch every control grows together, so a box and the button beside it stay one height. */
@media (pointer: coarse) { :root { --h-control: 44px; --h-sm: 40px; } }

/* ── States: a glyph and a word ───────────────────────────────────────── */
.badge {
    display: inline-flex; align-items: center; gap: 5px; height: 24px; padding: 0 8px;
    border-radius: 999px; border: 1px solid var(--line-2); background: var(--surface-2);
    font-size: var(--fs-caption); font-weight: 500; color: var(--ink-2); white-space: nowrap;
}
.badge svg { width: 13px; height: 13px; flex: none; }
.badge-pos { color: var(--pos-ink); background: var(--pos-wash); border-color: var(--pos-edge); }
.badge-caut { color: var(--caut-ink); background: var(--caut-wash); border-color: var(--caut-edge); }
.badge-neg { color: var(--neg-ink); background: var(--neg-wash); border-color: var(--neg-edge); }
.badge-info { color: var(--accent-ink); background: var(--accent-wash); border-color: transparent; }

.callout { display: flex; gap: var(--s-3); padding: var(--s-3) var(--s-4); border-radius: var(--r-control); border: 1px solid var(--line-2); background: var(--surface-2); }
.callout > * { min-width: 0; overflow-wrap: anywhere; }
.callout svg { width: 16px; height: 16px; flex: none; margin-top: 2px; }
.callout-pos { color: var(--pos-ink); background: var(--pos-wash); border-color: var(--pos-edge); }
.callout-neg { color: var(--neg-ink); background: var(--neg-wash); border-color: var(--neg-edge); }
.callout-caut { color: var(--caut-ink); background: var(--caut-wash); border-color: var(--caut-edge); }

/* ── Secrets, code ────────────────────────────────────────────────────── */
.secret {
    display: flex; gap: var(--s-2); align-items: center; justify-content: space-between;
    font-family: var(--mono); font-size: var(--fs-body); word-break: break-all;
    padding: var(--s-3) var(--s-4); background: var(--surface-2); border: 1px solid var(--line-2); border-radius: var(--r-control);
}
pre.env-block {
    margin: 0; padding: var(--s-4); overflow-x: auto;
    font: 400 var(--fs-caption)/1.7 var(--mono);
    background: var(--surface-2); border: 1px solid var(--line); border-radius: var(--r-control);
}
.qr { background: #fff; padding: var(--s-3); border-radius: var(--r-control); display: inline-block; line-height: 0; }
.qr svg { width: 180px; height: 180px; }
.codes { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-2) var(--s-5); font-family: var(--mono); }

.checklist { list-style: none; margin: 0; padding: 0; }
.checklist li { display: flex; gap: var(--s-3); align-items: flex-start; padding: var(--s-3) 0; border-top: 1px solid var(--line); }
.checklist li:first-child { border-top: 0; }
.checklist li > div { flex: 1; min-width: 0; }

.pagination { display: flex; gap: var(--s-2); justify-content: flex-end; padding: var(--s-4) var(--s-5); }

/* ── Guest pages ──────────────────────────────────────────────────────── */
/* The card holds the task alone: the way to the other one (sign in / sign up) under a line, what is for sale and the
   legal links under the card. Details a few want fold (`.opens`). */
.guest { min-height: 100vh; display: grid; grid-template-rows: 1fr auto; justify-items: center; align-items: center; gap: var(--s-6); padding: var(--s-5); background: var(--canvas); }
.guest .card { width: 100%; max-width: 400px; }
.guest .brand { margin-bottom: var(--s-5); }
.guest-alt { padding-top: var(--s-4); border-top: 1px solid var(--line); }
.opens-body.guest-steps { padding-left: 2rem; }
.guest-foot { display: grid; justify-items: center; gap: var(--s-2); max-width: 720px; text-align: center; }
.guest-foot footer { justify-content: center; gap: var(--s-1) var(--s-3); }

/* ── The legal footer (components/legal; 1.11.2026, the owner: at the very bottom of every page) ── */
/* The shell's last row, outside main (so it is the page's contentinfo), under the page and its project menu alike. The
   page takes what the window leaves, so on a short page the footer stands at the window's foot and after a long one
   where the page ends. Below 900 the shell is a column - the sidebar's row, the page, the footer - and keeps the
   window's height, so the canvas never stops short above the frame's tone. Quiet: the caption, the third ink, a
   hairline above, a link underlined on hover. id's own: the shell's block above is services' too, which has no footer. */
.shell { grid-template-rows: 1fr auto; }
.shell.has-side > .side { grid-row: 1 / -1; }
.page-foot { gap: var(--s-1) var(--s-4); padding: var(--s-4) var(--s-6); background: var(--canvas); border-top: 1px solid var(--line); }
.shell.has-side > .page-foot { border-left: 1px solid var(--line-chrome); }
.page-foot a { color: var(--ink-3); text-decoration: none; }
.page-foot a:hover { color: var(--ink); text-decoration: underline; }
@media (max-width: 900px) {
    .shell.has-side { display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: auto 1fr auto; min-height: calc(100vh - var(--h-top)); }
    .shell.has-side > .side { grid-row: auto; }
    .shell.has-side > .page-foot { border-left: 0; }
    .page-foot { padding-inline: var(--s-5); }
}
@media (max-width: 640px) { .page-foot { padding-inline: var(--s-4); } }
@media print {
    .shell, .shell.has-side { display: block; min-height: 0; }
    .page-foot, .shell.has-side > .page-foot { border: 0; background: none; }
}

/* ── Dialog (confirmations) ───────────────────────────────────────────── */
dialog.confirm {
    border: 1px solid var(--line); border-radius: var(--r-surface); padding: var(--s-5);
    background: var(--overlay); color: var(--ink); max-width: 440px; width: calc(100% - 32px);
    box-shadow: var(--shadow-float);
}
dialog.confirm::backdrop { background: oklch(20% 0.03 var(--hue) / 0.35); }

@media (max-width: 640px) {
    th, td { padding: 10px var(--s-4); }
    .codes { grid-template-columns: 1fr; }
}

/* Glyphs: the inner mark is cut out in the ground colour. */
.glyph { width: 16px; height: 16px; flex: none; }
.glyph-cut { stroke: var(--surface); }
.glyph-cut-fill { fill: var(--surface); }
.row-end { justify-content: flex-end; }
.mt-4 { margin-top: var(--s-4); }
.grow { flex: 1; min-width: 220px; }
input.input-sm { height: var(--h-sm); width: 180px; }
.add-row { display: flex; gap: var(--s-3); align-items: flex-start; flex-wrap: wrap; }
/* On a phone a row of fields stacks, one per line, so a label that wraps cannot push its box out of line. */
@media (max-width: 640px) { .add-row > .field { flex: 1 1 100%; min-width: 0; } .add-row > .field > .label[aria-hidden] { display: none; } }
.card-foot { padding: var(--s-4) var(--s-5) var(--s-5); border-top: 1px solid var(--line); }
.card.flush .card-head + .card-foot, .card.flush .card-head + form.card-foot { margin-top: var(--s-4); }

/* Toasts: a save or a refusal, in sight wherever the page landed. */
.toast {
    position: fixed; left: 50%; bottom: var(--s-5); transform: translateX(-50%); z-index: 20;
    width: max-content; max-width: calc(100% - 32px); align-items: center;
    box-shadow: var(--shadow-float);
}
.toast .btn-link { margin-left: var(--s-3); color: inherit; }


/* ── Products list (home) ──────────────────────────────────────────── */
.issue-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: var(--s-3); padding: var(--s-3) var(--s-5); border-top: 1px solid var(--line); align-items: center; }
.issue-row:first-child { border-top: 0; }
.issue-row .title { font-weight: 500; color: var(--ink); text-decoration: none; }
.issue-row .title:hover { color: var(--accent-ink); }
.issue-row .meta { color: var(--ink-3); font-size: var(--fs-caption); margin-top: 2px; }
/* A row that leads somewhere - its link marked data-row-link, which app.js follows from anywhere in the row (an
   .issue-row, a table's row, a list's item): the hand over all of it, and its link lit as when pointed at. */
:is(.issue-row, li, tr):has([data-row-link]) { cursor: pointer; }
.issue-row:has([data-row-link]):hover { background: var(--surface-2); }
.issue-row:has([data-row-link]):hover [data-row-link] { color: var(--accent-ink); }
:is(li, tr):has([data-row-link]):hover [data-row-link] { color: var(--accent); }
.mt-2 { margin-top: var(--s-2); }

/* ── Products (home): group by group, each product a card with its icon ─ */
.product-group + .product-group { margin-top: var(--s-6); }
.product-group-head { display: flex; align-items: baseline; gap: var(--s-1) var(--s-3); flex-wrap: wrap; margin-bottom: var(--s-3); }
.product-group-head h2 { font-size: var(--fs-lead); }
.product-group-head p { color: var(--ink-3); }
.product-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: var(--s-3); }
.product-card { display: flex; flex-direction: column; align-items: flex-start; gap: var(--s-1); padding: var(--s-4); background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-surface); color: var(--ink); text-decoration: none; transition: border-color 0.15s, box-shadow 0.15s; }
.product-card:not(.planned) { box-shadow: var(--shadow-card); }
a.product-card:hover { color: var(--ink); border-color: var(--line-2); box-shadow: 0 6px 18px var(--shade-1); }
.product-tile { display: grid; place-items: center; width: 44px; height: 44px; margin-bottom: var(--s-2); border-radius: var(--r-control); background: var(--accent-wash); color: var(--accent-ink); }
.product-tile .product-icon { width: 24px; height: 24px; }
.product-card-name { display: flex; align-items: center; gap: var(--s-2); font-weight: 600; }
a.product-card .product-card-name::after { content: '→'; color: var(--accent-ink); opacity: 0; transform: translateX(-4px); transition: opacity 0.15s, transform 0.15s; }
a.product-card:hover .product-card-name::after, a.product-card:focus-visible .product-card-name::after { opacity: 1; transform: none; }
.product-card-about { color: var(--ink-3); font-size: var(--fs-caption); line-height: 1.45; }
/* Who each product is for: the cards' pills, and the row above the groups that narrows the page to one audience
   (links on the kit's segmented track; the chosen one ringed as a checked segment is). */
.product-card-for { display: flex; flex-wrap: wrap; gap: 4px; margin-top: auto; padding-top: var(--s-2); }
.product-filter { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2) var(--s-3); margin-bottom: var(--s-5); }
.product-filter-label { color: var(--ink-3); font-size: var(--fs-caption); }
.product-filter-about { flex-basis: 100%; color: var(--ink-3); font-size: var(--fs-caption); }
.product-filter .segmented a { display: inline-flex; align-items: center; height: 30px; padding: 0 12px; border-radius: 7px; color: var(--ink-2); font-size: var(--fs-caption); font-weight: 500; text-decoration: none; white-space: nowrap; }
.product-filter .segmented a:hover { color: var(--ink); }
.product-filter .segmented a[aria-current] { background: var(--surface); color: var(--ink); box-shadow: 0 0 0 1px var(--ink-3), var(--shadow-card); }
.product-card.planned { background: transparent; border-style: dashed; }
.product-card.planned .product-tile { background: var(--surface-2); color: var(--ink-3); }
@media (prefers-reduced-motion: reduce) { .product-card, .product-card-name::after { transition: none; } }

/* Buying (/start, App\Billing): a package per product as cards, how often to pay, the total. */
/* The key above the cards: each kind of limit with its icon. */
.package-legend { display: grid; gap: var(--s-2); margin: 0 0 var(--s-4); padding: var(--s-3) var(--s-4); list-style: none; background: var(--surface-2); border-radius: var(--r-control); color: var(--ink-2); font-size: var(--fs-caption); }
.package-legend li { display: grid; grid-template-columns: 16px minmax(0, 1fr); gap: var(--s-2); }
.package-legend b { color: var(--ink); font-weight: 600; }
.package-product { border: 0; margin: 0; padding: var(--s-4) 0 0; min-width: 0; }
.package-product + .package-product { border-top: 1px solid var(--line); margin-top: var(--s-4); }
.package-product-name { display: flex; align-items: center; gap: var(--s-3); padding: 0; font-weight: 600; font-size: var(--fs-lead); }
.package-product-name .product-tile { margin: 0; }
/* A product's cards side by side, "None" the narrow one. Each card takes rows shared with the cards beside it (subgrid):
   its name, its price, then one per kind of limit (kinds-N: how many kinds its packages have), so a line that wraps
   moves that row down in every card. */
.package-options { display: grid; grid-template-columns: minmax(8.5rem, 0.7fr) repeat(3, minmax(0, 1fr)); gap: var(--s-3); margin-top: var(--s-3); }
.package-option {
    display: grid; grid-template-columns: 16px minmax(0, 1fr); grid-template-rows: subgrid; gap: var(--s-2); align-content: start;
    padding: var(--s-3) var(--s-4); border: 1px solid var(--line); border-radius: var(--r-surface); background: var(--surface); cursor: pointer;
}
.kinds-0 > .package-option { grid-row: span 2; }
.kinds-1 > .package-option { grid-row: span 3; }
.kinds-2 > .package-option { grid-row: span 4; }
.kinds-3 > .package-option { grid-row: span 5; }
.package-option > :not(input, .package-kind-icon) { grid-column: 2; }
.package-option > .package-kind-gap { grid-column: 1 / -1; }
.package-option input { align-self: start; width: 16px; height: 16px; margin: 2.5px 0 0; accent-color: var(--accent-ink); }
/* The whole card shows keyboard focus, and a chosen package a 2 px ring and the accent wash. */
.package-option input:focus-visible { outline: none; }
.package-option:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.package-option:hover { border-color: var(--line-2); }
.package-option:not(.package-option-none):has(input:checked) { border-color: var(--accent-ink); box-shadow: 0 0 0 1px var(--accent-ink); background: var(--accent-wash); }
/* "None" turns the product off for the project: quiet, and chosen it shows no more than its radio's dot. */
.package-option-none { border-style: dashed; background: none; }
/* Its note may wrap in the narrow column: it takes the rows below the name, so it never makes the price row taller. */
.package-option-none > .package-option-note { grid-row: 2 / -1; }
.package-option-name { font-weight: 600; }
.package-option-none .package-option-name { color: var(--ink-2); font-weight: 500; }
.package-option-note { color: var(--ink-3); font-size: var(--fs-caption); }
.package-option-price { color: var(--ink-3); font-size: var(--fs-caption); line-height: 1.4; font-variant-numeric: tabular-nums; }
.package-option-price b { color: var(--ink); font-size: var(--fs-title); font-weight: 600; letter-spacing: -0.01em; }
.package-option-price span { display: block; }
.package-kind-icon { width: 16px; height: 16px; margin-top: 2px; color: var(--ink-3); }
.package-kind { color: var(--ink-2); font-size: var(--fs-caption); }
.package-kind b { color: var(--ink); font-weight: 600; font-variant-numeric: tabular-nums; }
@media (max-width: 900px) {
    /* "None" a slim row of its own above three columns. */
    .package-options { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    .package-options > .package-option-none { grid-column: 1 / -1; grid-row: auto; grid-template-rows: none; grid-template-columns: 16px auto minmax(0, 1fr); align-items: baseline; }
    .package-option-none > .package-option-note { grid-column: 3; grid-row: auto; }
}
@media (max-width: 640px) {
    /* A card a row, its price right of its name. */
    .package-options { grid-template-columns: minmax(0, 1fr); gap: var(--s-2); }
    .package-options > .package-option:not(.package-option-none) { grid-row: auto; grid-template-rows: none; grid-template-columns: 16px minmax(0, 1fr) auto; }
    .package-option > .package-kind { grid-column: 2 / -1; }
    .package-option > .package-option-price { grid-column: 3; grid-row: 1; text-align: right; }
    .package-option > .package-kind-gap { display: none; }
}
.choice-row { display: flex; gap: var(--s-2) var(--s-5); flex-wrap: wrap; }
.choice-row label { display: inline-flex; gap: var(--s-2); align-items: center; cursor: pointer; }
.card > .error { color: var(--neg-ink); font-size: var(--fs-caption); display: flex; gap: 6px; align-items: center; margin-top: var(--s-3); }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* The price list (/start): every product's table puts its columns in the same place, whatever its words, so the prices
   line up from one product to the next (01.11.2026). Narrower than its least, it scrolls in its .table-wrap. */
.price-table { table-layout: fixed; min-width: 40rem; }
.price-table-package { width: 9rem; }
.price-table-price { width: 10rem; }
/* The price list read as a page (2.11.2026, the owner: text a window wide and a screenshot as wide between each product
   made it "massive and hard to read"): one column, centred, as wide as a line can be read in the products' words;
   the head's words larger; the products at a glance as cards that lead to their parts. */
.prices { display: grid; gap: var(--s-5); width: 100%; max-width: 76rem; margin-inline: auto; }
.prices-hero { display: grid; gap: var(--s-3); justify-items: start; padding: var(--s-3) 0 var(--s-1); }
.prices-hero h1 { font-size: 2rem; letter-spacing: -0.02em; }
.prices-hero p { max-width: 44rem; color: var(--ink-2); font-size: var(--fs-lead); line-height: 1.6; }
.prices-index { display: grid; grid-template-columns: repeat(auto-fill, minmax(15.5rem, 1fr)); gap: var(--s-3); }
.prices-index-item { display: flex; gap: var(--s-3); align-items: flex-start; padding: var(--s-3) var(--s-4); border: 1px solid var(--line); border-radius: var(--r-surface); background: var(--surface); box-shadow: var(--shadow-card); color: var(--ink); text-decoration: none; transition: border-color 0.12s, box-shadow 0.12s; }
.prices-index-item:hover { color: var(--ink); border-color: var(--line-2); box-shadow: var(--shadow-raised); }
.prices-index-item .product-tile { width: 36px; height: 36px; margin: 0; flex: none; }
.prices-index-words { display: grid; gap: 2px; min-width: 0; }
.prices-index-words > span { color: var(--ink-3); font-size: var(--fs-caption); line-height: 1.45; }
.prices-index-words > .prices-from { margin-top: var(--s-1); color: var(--ink-2); font-weight: 500; font-variant-numeric: tabular-nums; }
/* "How it works": the four steps of buying and using one, side by side, each under its number. */
.how-steps { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s-4) var(--s-5); margin: var(--s-4) 0 0; padding: 0; list-style: none; counter-reset: step; color: var(--ink-2); }
.how-steps li { display: grid; gap: var(--s-2); align-content: start; counter-increment: step; }
.how-steps li::before { content: counter(step); display: grid; place-items: center; width: 28px; height: 28px; border-radius: 50%; background: var(--accent-wash); color: var(--accent-ink); font-size: var(--fs-caption); font-weight: 600; }
/* What paying means: a fact each, its name above its words. */
.terms-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(17rem, 1fr)); gap: var(--s-4) var(--s-6); margin: var(--s-4) 0 0; }
.terms-grid > div { display: grid; gap: var(--s-1); align-content: start; }
.terms-grid dt { color: var(--ink); font-weight: 600; }
.terms-grid dd { margin: 0; color: var(--ink-2); }
/* A product: its words - name and summary beside its tile, what it does, its key features ticked - beside its first
   screenshot, framed, then its packages. The screenshot is a button: pressed, every screenshot of it large. */
.price-intro { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 27rem); gap: var(--s-5) var(--s-6); align-items: start; padding: var(--s-5); }
.price-words { display: grid; gap: var(--s-3); max-width: 42rem; }
.price-words > p { color: var(--ink-2); line-height: 1.6; }
.price-name { display: flex; gap: var(--s-3); align-items: center; }
.price-name .product-tile { margin: 0; flex: none; }
.price-summary { color: var(--ink-2); font-weight: 500; }
.price-highlights { display: grid; gap: 6px; margin: 0; padding: 0; list-style: none; }
.price-highlights li { display: flex; gap: var(--s-2); align-items: flex-start; color: var(--ink-2); }
.price-highlights .glyph { width: 16px; height: 16px; flex: none; margin-top: 2px; color: var(--pos-ink); }
.price-shot { display: grid; gap: var(--s-2); margin: 0; }
.price-shot-open { position: relative; display: block; width: 100%; padding: 0; overflow: hidden; border: 1px solid var(--line); border-radius: var(--r-control); background: var(--surface-2); box-shadow: var(--shadow-card); cursor: zoom-in; transition: box-shadow 0.15s, transform 0.15s; }
.price-shot-open:hover { box-shadow: var(--shadow-raised); transform: translateY(-1px); }
.price-shot-open img { display: block; width: 100%; height: auto; aspect-ratio: 16 / 10; object-fit: cover; object-position: top left; }
.price-shot-more { position: absolute; right: var(--s-2); bottom: var(--s-2); display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; border: 1px solid var(--line-2); border-radius: 999px; background: var(--raised); box-shadow: var(--shadow-card); color: var(--ink); font-size: var(--fs-caption); font-weight: 500; }
.price-shot-more svg { width: 14px; height: 14px; }
.price-shot figcaption { color: var(--ink-3); font-size: var(--fs-caption); }
.price-product > .table-wrap { border-top: 1px solid var(--line); }
@media (prefers-reduced-motion: reduce) {
    .price-shot-open, .prices-index-item { transition: none; }
    .price-shot-open:hover { transform: none; }
}
/* Its screenshots large, one under the other with their captions, in a dialog nearly the window's size; Close or Escape. */
dialog.shot-dialog { width: min(76rem, calc(100% - 32px)); max-width: none; max-height: calc(100% - 32px); margin: auto; padding: 0; border: 1px solid var(--line); border-radius: var(--r-surface); background: var(--overlay); color: var(--ink); box-shadow: var(--shadow-float); }
dialog.shot-dialog::backdrop { background: oklch(20% 0.03 var(--hue) / 0.55); }
.shot-dialog-head { position: sticky; top: 0; z-index: 1; display: flex; align-items: center; gap: var(--s-3); padding: var(--s-3) var(--s-5); border-bottom: 1px solid var(--line); background: var(--overlay); }
.shot-dialog-head .product-tile { width: 32px; height: 32px; margin: 0; flex: none; }
.shot-dialog-head h2 { flex: 1; min-width: 0; font-size: var(--fs-lead); }
.shot-dialog-body { display: grid; gap: var(--s-6); padding: var(--s-5); }
.shot-dialog-body figure { display: grid; gap: var(--s-2); margin: 0; }
.shot-dialog-body img { display: block; width: 100%; height: auto; border: 1px solid var(--line); border-radius: var(--r-control); }
.shot-dialog-body figcaption { color: var(--ink-2); }
/* The way in, once more under the products. */
.prices-cta { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3) var(--s-5); flex-wrap: wrap; }
.prices-cta p { max-width: 44rem; }
@container page (max-width: 900px) {
    .how-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .price-intro { grid-template-columns: minmax(0, 1fr); }
    .price-shot { max-width: 34rem; }
}
/* On a phone the products at a glance are two columns of names and prices (each one's words are in its part below), and
   a package is three lines - its name, its limits, both prices - instead of a table scrolled sideways past its prices. */
@container page (max-width: 520px) {
    .how-steps { grid-template-columns: minmax(0, 1fr); }
    .prices-hero h1 { font-size: var(--fs-display); }
    .prices-index { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-2); }
    .prices-index-item { padding: var(--s-3); gap: var(--s-2); }
    .prices-index-item .product-tile { width: 28px; height: 28px; }
    .prices-index-words > span:not(.prices-from) { display: none; }
    .prices-index-words > .prices-from { margin-top: 0; font-weight: 400; }
    .price-intro { padding: var(--s-4); }
    .price-table { min-width: 0; table-layout: auto; }
    .price-table colgroup, .price-table thead { display: none; }
    .price-table tbody { display: block; }
    .price-table tr { display: flex; flex-wrap: wrap; gap: 2px var(--s-3); padding: var(--s-3) var(--s-4); border-top: 1px solid var(--line); }
    .price-table tr:first-child { border-top: 0; }
    .price-table td { display: block; padding: 0; border: 0; }
    .price-table td:nth-child(-n+2) { flex-basis: 100%; }
    .price-table td:nth-child(2) { color: var(--ink-2); }
    .price-table td.num { margin-top: var(--s-1); text-align: left; }
    .shot-dialog-body { padding: var(--s-3); gap: var(--s-5); }
}
.total-row td { font-weight: 600; border-top: 1px solid var(--line-2); }
/* The total and the button stay in sight at the bottom while products are chosen. */
.purchase-bar { position: sticky; bottom: var(--s-3); z-index: 2; display: flex; align-items: center; justify-content: space-between; gap: var(--s-3) var(--s-5); flex-wrap: wrap; padding: var(--s-3) var(--s-4); background: var(--raised); border: 1px solid var(--line-2); border-radius: var(--r-surface); box-shadow: var(--shadow-raised); }
.purchase-total { margin: 0; font-weight: 600; font-size: var(--fs-lead); font-variant-numeric: tabular-nums; }
/* Buying: the accounts, a numbered row each (the buyer's own first; app.js adds and removes the others), "Add account"
   under them, and the overview of the whole purchase above the bar. */
.account-rows { display: grid; gap: var(--s-3); margin: 0; padding: 0; list-style: none; }
.account-row { display: grid; grid-template-columns: 28px minmax(0, 1fr) auto; gap: var(--s-3); align-items: start; padding-top: var(--s-3); border-top: 1px solid var(--line); }
.account-row-own { grid-template-columns: 28px minmax(0, 1fr); border-top: 0; padding-top: 0; }
.account-row p { margin: 0; padding-top: 3px; overflow-wrap: anywhere; }
.account-row-number { display: grid; place-items: center; width: 28px; height: 28px; border-radius: 50%; background: var(--surface-2); color: var(--ink-2); font-size: var(--fs-caption); font-weight: 600; font-variant-numeric: tabular-nums; }
/* In a row of fields, level with the boxes rather than their labels. */
.account-row-number:has(+ .fields), .account-remove { margin-top: 27px; }
/* `hidden` wins over .btn's display: the buttons app.js shows once it runs. */
.account-row .btn[hidden], .account-add .btn[hidden] { display: none; }
.account-add { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s-2) var(--s-3); margin-top: var(--s-4); padding-top: var(--s-4); border-top: 1px solid var(--line); }
@media (max-width: 559px) {
    /* The fields stack; "Remove" goes under them. */
    .account-row { grid-template-columns: 28px minmax(0, 1fr); }
    .account-remove { grid-column: 2; justify-self: start; margin-top: 0; }
}
.overview tfoot td { color: var(--ink-2); }
.overview tfoot .total-row td { color: var(--ink); }
.overview tbody tr:hover { background: none; }

/* A workspace's roles (workspaces/roles, ../ACCESS.md): one radio per product and level, what more a product has under it. */
.levels th[scope="row"] { font-weight: 500; text-align: left; white-space: nowrap; }
.levels td { text-align: center; }
.levels .level-choice { display: inline-flex; padding: var(--s-2); cursor: pointer; }
.levels .level-choice input, .levels .level-more input { width: 16px; height: 16px; margin: 0; accent-color: var(--primary); }
.levels .level-more td { text-align: left; padding-top: 0; }
.levels .level-more fieldset { border: 0; margin: 0 0 var(--s-2); padding: 0; display: grid; gap: var(--s-1); }
.levels .level-more .check { margin-top: var(--s-1); }
.levels tbody tr.level-more:hover { background: none; }
.role-about, .role-grant { display: block; }
.role-what { margin-top: var(--s-1); }
.role-what li { list-style: none; }
.accounts-row { display: flex; gap: var(--s-3); align-items: center; justify-content: space-between; flex-wrap: wrap; }
.accounts-row p { color: var(--ink-2); }

/* A workspace's projects (workspaces/show): each with its products as doors - icon and name -, each opening the project
   in that product at the workspace's address. They wrap under the name on a narrow screen. */
.project-row { grid-template-columns: minmax(160px, 1fr) minmax(0, 2.5fr); align-items: start; }
.project-doors { display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; margin: 0; }
.project-door { display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 10px 0 8px; border: 1px solid var(--line); border-radius: var(--r-control); background: var(--surface); color: var(--ink); font-size: var(--fs-caption); font-weight: 500; text-decoration: none; white-space: nowrap; }
.project-door:hover { border-color: var(--line-2); color: var(--ink); box-shadow: var(--shadow-card); }
.project-door .product-icon { width: 16px; height: 16px; color: var(--accent-ink); }
p.project-doors { align-self: center; }
@media (max-width: 720px) { .project-row { grid-template-columns: minmax(0, 1fr); } .project-doors { justify-content: flex-start; } }
/* A workspace's products (workspaces/products): under each product, its projects as doors; then the ones not in it yet,
   as a quiet list of names - no door, since no project has them. */
.product-projects { justify-content: flex-start; margin-top: var(--s-2); }
.absent-products { margin-top: var(--s-6); }
.absent-list { display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-4); margin: 0; padding: 0; list-style: none; color: var(--ink-2); }
.absent-list li { display: inline-flex; align-items: center; gap: 6px; }
.absent-list .product-icon { width: 16px; height: 16px; color: var(--ink-3); }
.absent-for { color: var(--ink-3); font-size: var(--fs-caption); }

/* A form in a dialog (components/dialog): adding to a list, renaming - opened by a button, the fields one under the
   other, Cancel and the action at the foot. The same sheet as the confirmation's, a little wider. */
dialog.form-dialog {
    /* In the middle of the window: a page's .stack spacing would push it to the top. */
    margin: auto; border: 1px solid var(--line); border-radius: var(--r-surface); padding: var(--s-5);
    background: var(--overlay); color: var(--ink); max-width: 520px; width: calc(100% - 32px);
    box-shadow: var(--shadow-float);
}
dialog.form-dialog::backdrop { background: oklch(20% 0.03 var(--hue) / 0.35); }
.form-dialog-head { margin-bottom: var(--s-4); }
.form-dialog-head p { color: var(--ink-3); margin-top: 2px; }
.form-dialog-body { display: grid; gap: var(--s-4); }
.form-dialog-body .fields { grid-template-columns: minmax(0, 1fr); max-width: none; }
/* A page's head with more than one action (People: Invite someone, Add from the workspace). */
.page-actions { display: flex; gap: var(--s-2); flex-wrap: wrap; }
/* A list's row whose actions are buttons that open dialogs (a project's environments). */
.list .row-actions { display: flex; gap: var(--s-2); align-items: center; flex-wrap: wrap; justify-content: flex-end; }
.you { color: var(--ink-3); font-size: var(--fs-caption); }
/* A choice of one, each with what it means (a role in a dialog): radios under a legend. */
fieldset.choices { border: 0; margin: 0; padding: 0; min-width: 0; gap: var(--s-2); }
fieldset.choices legend { padding: 0; margin-bottom: 6px; }
fieldset.choices .check { width: auto; align-items: flex-start; }
fieldset.choices .check input { margin-top: 3px; }
fieldset.choices .choices-head { color: var(--ink-3); font-size: var(--fs-caption); margin-top: var(--s-2); }
/* A card's head with an action: the words take the room and wrap, the action stays on the right (Environments: Add). */
.card-head > div:first-child:not(:last-child) { flex: 1 1 18rem; }

/* ── Workspace colours (Workspaces\Enums\WorkspaceColor) ──────────────── */
/* A workspace's mark: its first letter on its colour, beside its name - never the only sign of which it is. Each colour
   is dark enough under a white letter (4.5:1 or more) in both looks. */
.ws-mark { display: inline-grid; place-items: center; flex: none; width: 22px; height: 22px; border-radius: 6px; color: #fff; font-size: 12px; font-weight: 600; line-height: 1; box-shadow: inset 0 0 0 1px rgb(0 0 0 / 0.08); }
.ws-mark.ws-lg { width: 40px; height: 40px; border-radius: 10px; font-size: 18px; }
.ws-mark.ws-sm { width: 16px; height: 16px; border-radius: 4px; font-size: 10px; }
.ws-blue { background: #2563eb; }
.ws-green { background: #15803d; }
.ws-orange { background: #c2410c; }
.ws-purple { background: #9333ea; }
.ws-teal { background: #0f766e; }
.ws-pink { background: #be185d; }
.ws-amber { background: #b45309; }
.ws-red { background: #b91c1c; }
.ws-indigo { background: #4f46e5; }
.ws-slate { background: #475569; }
/* The list of workspaces: the mark, then the name and its address; on the right its role and the way to its settings. */
.ws-row { display: flex; align-items: center; gap: var(--s-3); min-width: 0; }
.ws-row > div { min-width: 0; }
.ws-actions { display: flex; align-items: center; gap: var(--s-3); color: var(--ink-2); }
.ws-actions .nav-icon { width: 15px; height: 15px; color: var(--ink-3); }
/* On a phone the address keeps its line: the button is its gear alone, its word still read out. */
@media (max-width: 520px) {
    .ws-actions { gap: var(--s-2); }
    .ws-actions .btn { padding: 0 10px; }
    .ws-actions .ws-btn-text { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
}
/* General's colour: each a swatch with its name, the chosen one ringed and its name in bold. */
.ws-colors { display: flex; flex-wrap: wrap; gap: var(--s-2); border: 0; padding: 0; margin: 0; }
.ws-colors label { display: inline-flex; align-items: center; gap: 8px; padding: 6px 10px 6px 6px; border: 1px solid var(--line-control); border-radius: var(--r-control); cursor: pointer; background: var(--surface); }
.ws-colors input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.ws-colors input:checked + .ws-mark { box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--ink); }
.ws-colors label:has(input:checked) { border-color: var(--ink); font-weight: 600; }
.ws-colors label:has(input:focus-visible) { outline: 2px solid var(--focus, var(--ink)); outline-offset: 2px; }

/* ── Subscription (billing/subscription) ─────────────────────────────── */
/* Where it stands: the total a period large on the left, the facts beside it, cancel or keep on the right; a callout
   under them when it is ending, in grace or over. */
.plan { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: var(--s-4) var(--s-6); align-items: center; }
.plan-total { padding-right: var(--s-6); border-right: 1px solid var(--line); }
.plan-label, .plan-facts dt { color: var(--ink-3); font-size: var(--fs-caption); font-weight: 500; }
.plan-amount { margin-top: 2px; color: var(--ink-3); font-variant-numeric: tabular-nums; white-space: nowrap; }
.plan-amount b { color: var(--ink); font-size: 2rem; font-weight: 600; letter-spacing: -0.02em; line-height: 1.15; }
.plan-split { color: var(--ink-3); font-size: var(--fs-caption); font-variant-numeric: tabular-nums; }
.plan-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); gap: var(--s-4) var(--s-5); margin: 0; }
.plan-facts dd { display: flex; align-items: center; flex-wrap: wrap; gap: 4px var(--s-2); margin: 4px 0 0; color: var(--ink); }
.plan-actions { align-self: start; }
.plan > .callout { grid-column: 1 / -1; margin: 0; align-items: center; }
.plan > .callout svg { margin-top: 0; }
@media (max-width: 900px) {
    .plan { grid-template-columns: minmax(0, 1fr) auto; }
    .plan-total { padding-right: 0; border-right: 0; }
    .plan-facts { grid-column: 1 / -1; grid-row: 2; padding-top: var(--s-4); border-top: 1px solid var(--line); }
}
.bill-section-head { display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--s-1) var(--s-3); margin-top: var(--s-6); }
.bill-section-head h2 { font-size: var(--fs-lead); }
.bill-section-head p { color: var(--ink-3); }

/* A project: a sheet that folds. Its head - the chevron, the name, the products' icons, the total - is the summary. */
.bill > summary { list-style: none; }
.bill > summary::-webkit-details-marker { display: none; }
.bill-head { display: grid; grid-template-columns: 16px minmax(0, 1fr) auto auto; align-items: center; gap: var(--s-3) var(--s-5); padding: var(--s-4) var(--s-5); cursor: pointer; user-select: none; }
.bill-head:hover { background: var(--surface-2); }
.bill[open] > .bill-head { border-bottom: 1px solid var(--line); }
.bill-chevron { width: 16px; height: 16px; color: var(--ink-3); transform: rotate(-90deg); transition: transform 0.15s; }
.bill[open] .bill-chevron { transform: none; }
.bill-name { display: flex; align-items: baseline; flex-wrap: wrap; gap: 2px var(--s-2); min-width: 0; }
.bill-title { font-size: var(--fs-lead); font-weight: 600; color: var(--ink); overflow-wrap: anywhere; }
.bill-slug { color: var(--ink-3); font-size: var(--fs-caption); }
.bill-icons { display: flex; align-items: center; gap: 4px; }
.bill-icon { display: grid; place-items: center; width: 28px; height: 28px; border-radius: 8px; background: var(--accent-wash); color: var(--accent-ink); }
.bill-icon .product-icon { width: 16px; height: 16px; }
.bill-count { margin-left: var(--s-2); color: var(--ink-3); font-size: var(--fs-caption); white-space: nowrap; }
.bill-sum { min-width: 7.5rem; text-align: right; color: var(--ink-3); font-size: var(--fs-caption); white-space: nowrap; font-variant-numeric: tabular-nums; }
.bill-sum b { color: var(--ink); font-size: var(--fs-title); font-weight: 600; letter-spacing: -0.01em; }
@media (prefers-reduced-motion: reduce) { .bill-chevron { transition: none; } }

/* Its lines: a product's tile, its name, package and limits, its price, Change. */
.bill-lines { margin: 0; padding: 0; list-style: none; }
.bill-line { display: grid; grid-template-columns: 36px minmax(0, 1fr) 7.5rem 5.5rem; align-items: center; gap: var(--s-2) var(--s-4); padding: var(--s-3) var(--s-5); border-top: 1px solid var(--line); }
.bill-line:first-child { border-top: 0; }
.bill-lines.is-read-only .bill-line { grid-template-columns: 36px minmax(0, 1fr) 7.5rem; }
.bill-line:has([data-row-link]):hover { background: var(--surface-2); }
.bill-line:has([data-row-link]):hover [data-row-link] { color: var(--accent-ink); }
.bill-line > .product-tile { width: 36px; height: 36px; margin: 0; }
.bill-line > .product-tile .product-icon { width: 20px; height: 20px; }
.product-tile.is-plain { background: var(--surface-2); color: var(--ink-2); }
.bill-what-head { display: flex; align-items: center; flex-wrap: wrap; gap: 2px var(--s-2); }
.bill-what .title { font-weight: 600; color: var(--ink); text-decoration: none; }
.bill-limits { display: flex; flex-wrap: wrap; gap: 2px var(--s-4); margin-top: 4px; color: var(--ink-3); font-size: var(--fs-caption); }
.bill-limits > span { display: inline-flex; align-items: center; gap: 6px; }
.bill-limits .product-icon { width: 14px; height: 14px; flex: none; }
.bill-limits b { color: var(--ink-2); font-weight: 600; }
.bill-price { text-align: right; color: var(--ink-3); font-size: var(--fs-caption); white-space: nowrap; font-variant-numeric: tabular-nums; }
.bill-price b { color: var(--ink); font-size: var(--fs-body); font-weight: 600; }
.bill-price small { display: block; color: var(--pos-ink); font-size: var(--fs-caption); }
.bill-included { color: var(--ink-3); }
.bill-line > .btn { justify-self: end; }
.bill-none { display: block; color: var(--ink-3); }
/* An add-on's line (../ADDONS.md) sits under its product's, a step in, its tile plain. */
.bill-addon { padding-left: calc(var(--s-5) + 18px); border-top-style: dashed; }
.bill-addon > .product-tile.is-plain { background: var(--surface-2); color: var(--ink-3); }
/* Its dialog: − the number + in one row, the words after them. */
.addon-stepper { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s-2); margin-top: var(--s-3); }
.addon-stepper label { margin: 0; }
.addon-stepper input[type="number"] { width: 4.5rem; text-align: center; font-variant-numeric: tabular-nums; }
.addon-step { width: 36px; padding: 0; font-size: var(--fs-lead); line-height: 1; }
.addon-stepper-words { color: var(--ink-3); font-size: var(--fs-caption); }

/* Under the lines: the products it has not, each a chip that opens its packages; then a word on its discount and its page. */
.bill-foot { padding: var(--s-4) var(--s-5); border-top: 1px solid var(--line); background: var(--surface-2); }
.bill-add + .bill-foot-note { margin-top: var(--s-4); }
.bill-add-head { margin-bottom: var(--s-2); color: var(--ink-2); font-size: var(--fs-caption); font-weight: 600; }
.bill-chips { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.bill-chip { display: inline-flex; align-items: center; gap: 6px; height: 32px; padding: 0 10px 0 8px; border: 1px solid var(--line-2); border-radius: var(--r-control); background: var(--surface); color: var(--ink); font: 500 var(--fs-caption)/1 var(--font); white-space: nowrap; cursor: pointer; }
.bill-chip .product-icon { width: 16px; height: 16px; color: var(--ink-3); }
.bill-chip:hover { border-color: var(--accent-ink); background: var(--accent-wash); color: var(--accent-ink); }
.bill-chip:hover .product-icon { color: var(--accent-ink); }
.bill-chip-from { color: var(--ink-3); font-weight: 400; }
.bill-foot-note { display: flex; flex-wrap: wrap; justify-content: space-between; gap: var(--s-2) var(--s-4); color: var(--ink-3); font-size: var(--fs-caption); }
.bill-foot-note a { margin-left: auto; }
@media (max-width: 720px) {
    /* The head wraps: the name and the total on one line, the icons under them. */
    .bill-head { grid-template-columns: 16px minmax(0, 1fr) auto; padding: var(--s-3) var(--s-4); }
    .bill-icons { grid-column: 2 / -1; grid-row: 2; }
    .bill-sum { min-width: 0; }
    /* A line: the tile, the name with the price beside it, the limits across under them, then Change. */
    .bill-line, .bill-lines.is-read-only .bill-line { grid-template-columns: 28px minmax(0, 1fr) auto; grid-template-areas: 'tile head price' 'tile limits limits' 'tile act act'; align-items: start; padding: var(--s-3) var(--s-4); }
    .bill-line > .product-tile { grid-area: tile; width: 28px; height: 28px; border-radius: 8px; }
    .bill-line > .product-tile .product-icon { width: 16px; height: 16px; }
    .bill-what { display: contents; }
    .bill-what-head { grid-area: head; min-height: 28px; }
    .bill-limits { grid-area: limits; margin-top: 0; }
    .bill-price { grid-area: price; padding-top: 4px; }
    .bill-line > .btn { grid-area: act; justify-self: start; }
    .bill-line > span:empty { display: none; }
    .bill-foot { padding: var(--s-3) var(--s-4); }
}

/* What waits for the renewal (../SUBSCRIPTIONS.md, "Changing it"): a badge beside the package, "Keep …" beside it; a
   line's own form (Remove one) where Change stands; under a dialog's cards, what the choice costs. */
.bill-keep { display: inline; }
.bill-keep .btn-link { font-size: var(--fs-caption); }
.bill-line > form { justify-self: end; }
.package-choice-note { margin: var(--s-3) 0 0; color: var(--ink-2); font-size: var(--fs-caption); line-height: 1.5; }
.package-choice-note:empty { display: none; }
@media (max-width: 720px) { .bill-line > form { grid-area: act; justify-self: start; } }

/* A dialog of package cards: wider, the product's tile beside its title, the card it has marked "Now". */
dialog.form-dialog.form-dialog-wide { max-width: 860px; }
.form-dialog-head.has-icon { display: flex; align-items: center; gap: var(--s-3); }
.form-dialog-head.has-icon .product-tile { flex: none; margin: 0; }
.form-dialog-wide .package-options { margin-top: 0; }
.package-option-current { margin-left: 6px; padding: 1px 7px; border-radius: 999px; background: var(--surface); border: 1px solid var(--accent-ink); color: var(--accent-ink); font-size: 11px; font-weight: 600; vertical-align: 1px; }
/* Two packages, not three; adding has no "None". */
.package-options.packages-2 { grid-template-columns: minmax(8.5rem, 0.7fr) repeat(2, minmax(0, 1fr)); }
.package-options.package-options-add { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.package-options.package-options-add.packages-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
@media (max-width: 900px) {
    .package-options.packages-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
    .package-options.packages-2, .package-options.package-options-add, .package-options.package-options-add.packages-2 { grid-template-columns: minmax(0, 1fr); }
}


/* ── The kit (30.10.2026, the owner: every page as good as the Subscription page): the pieces rows and settings are
   drawn with everywhere - a pill, a person, a row's "⋯", a row led by a tile, a setting with its foot, a preference
   row, a sticky form bar, a segmented choice, choice cards, an empty list, a table that stacks on a phone. One block,
   so another app (services) copies it whole. ─────────── */
/* What stacks on a phone asks how wide the page is, not the window (the container "page": the page, or beside a
   project's menu its body), so it stacks beside two sidebars too. 608px is the page in a 640px window, less its 16px a
   side; 672px the page in a 720px window, less its 24px a side. */
.page, .page-body { container: page / inline-size; }
/* A pill: a role, a kind, a package - a word in a rounded frame. Never a state: that is x-badge, a glyph and a word. */
.pill { display: inline-flex; align-items: center; gap: 4px; height: 22px; padding: 0 8px; border: 1px solid var(--line-2); border-radius: 999px; background: var(--surface); color: var(--ink-2); font-size: var(--fs-caption); font-weight: 500; line-height: 1; white-space: nowrap; vertical-align: middle; }
.pill-accent { border-color: transparent; background: var(--accent-wash); color: var(--accent-ink); }
.pill-pos { border-color: transparent; background: var(--pos-wash); color: var(--pos-ink); }
.pill .product-icon, .pill .nav-icon { width: 13px; height: 13px; }

/* Someone (components/person): their disc in their colour - the letter white on it in either look, as a workspace's
   mark -, their name, their address under it. */
.person { display: inline-flex; align-items: center; gap: var(--s-3); min-width: 0; vertical-align: middle; }
.person > .avatar { width: 32px; height: 32px; color: #fff; font-size: 13px; }
.person-text { display: flex; flex-direction: column; min-width: 0; line-height: 1.35; }
.person-name { color: var(--ink); font-weight: 500; overflow-wrap: anywhere; }
.person-email { color: var(--ink-3); font-size: var(--fs-caption); overflow-wrap: anywhere; }

/* A row's "⋯" (components/row-menu): a quiet square button, its menu hanging right-aligned under it - or, where the
   window has no room for that (a phone, "⋯" under its row's words), from its left or moved in: app.js places it. */
.btn-icon { width: var(--h-sm); padding: 0; }
.row-menu { position: relative; display: inline-block; vertical-align: middle; }
.row-menu > summary { list-style: none; }
.row-menu > summary::-webkit-details-marker { display: none; }
.row-menu > summary.btn { border-color: transparent; background: none; color: var(--ink-3); }
.row-menu > summary.btn:hover, .row-menu[open] > summary.btn { border-color: var(--line-2); background: var(--surface-2); color: var(--ink); }
.row-menu-dots { width: 16px; height: 16px; fill: currentColor; }
.row-menu > .menu { min-width: 210px; max-width: calc(100vw - 2 * var(--s-2)); text-align: left; white-space: normal; }
.row-menu form { margin: 0; }
.menu-item.is-danger { color: var(--neg-ink); }
.menu-item.is-danger:hover, .menu-item.is-danger:focus-visible { background: var(--neg-wash); color: var(--neg-ink); }
.menu-item.is-danger > .nav-icon { color: currentColor; }
.menu-sep { height: 1px; margin: 4px 2px; background: var(--line); }
/* A sheet that clips its rows to its rounded corners lets an open menu hang out of it. */
.card.flush:has(.row-menu[open]), .table-wrap:has(.row-menu[open]) { overflow: visible; }

/* A row led by a tile - a product's icon (.product-tile) or a project's letter (.letter-tile) -, its words, then
   what it shows and does on the right (.row-side). */
.issue-row.has-tile { grid-template-columns: 36px minmax(0, 1fr) auto; }
.issue-row > .product-tile, .letter-tile { width: 36px; height: 36px; margin: 0; border-radius: var(--r-control); }
.issue-row > .product-tile .product-icon { width: 20px; height: 20px; }
.letter-tile { display: grid; place-items: center; flex: none; border: 1px solid var(--line); background: var(--surface-2); color: var(--ink-2); font-size: 15px; font-weight: 600; text-transform: uppercase; }
.row-side { display: flex; align-items: center; justify-content: flex-end; flex-wrap: wrap; gap: var(--s-2); }
/* Its facts, a dot between two: the dot stands in the gap before the second, outside its box - never underlined with
   a link, cut with an address or drawn in a badge's frame (a badge or a pill has none) - and a line that wraps starts
   without one, clipped sideways only; the 4px inside the clip keep a focus ring whole (31.10.2026, Errors' way). */
.row-meta { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: 2px 1.5rem; margin: 3px -4px 0; padding-inline: 4px; overflow-x: clip; color: var(--ink-3); font-size: var(--fs-caption); }
.row-meta > * + *::before { content: '·'; position: absolute; width: 1.5rem; margin-left: -1.5rem; color: var(--line-control); font-family: var(--font); text-align: center; }
.row-meta > :is(.badge, .pill)::before { content: none; }
/* An address or a slug too long for its line ends in "…" rather than running under what is beside it. */
.row-meta > .mono { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@container page (max-width: 608px) {
    .issue-row.has-tile { grid-template-columns: 36px minmax(0, 1fr); }
    .issue-row.has-tile > .row-side { grid-column: 2; justify-content: flex-start; }
}

/* A setting (General, a project's name, Preferences, Security): a sheet with its title, its words and its control,
   and a foot - what to know on the left, the one action on the right. The whole sheet is the form. */
.card.setting { padding: 0; overflow: hidden; }
.setting-body { display: grid; gap: var(--s-4); padding: var(--s-5); }
.setting-head p { margin-top: 2px; color: var(--ink-3); }
.setting-body > .field, .setting-body > .fields > .field { max-width: 30rem; }
.setting-foot { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s-2) var(--s-4); min-height: 56px; padding: var(--s-3) var(--s-5); border-top: 1px solid var(--line); background: var(--surface-2); color: var(--ink-3); font-size: var(--fs-caption); }
.setting-foot > :last-child:not(:first-child) { margin-left: auto; }
.setting-foot > .btn:only-child, .setting-foot > form:only-child { margin-left: auto; }
.person.is-compact { gap: var(--s-2); }
.person.is-compact > .avatar { width: 24px; height: 24px; font-size: 11px; }
/* A list of preferences a row: what it is and what it does on the left, its control on the right; stacked on a phone. */
.pref-row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(16rem, 24rem); align-items: center; gap: var(--s-3) var(--s-6); padding: var(--s-4) var(--s-5); border-top: 1px solid var(--line); }
.card.flush > .pref-row:first-child { border-top: 0; }
.pref-text { display: grid; gap: 2px; min-width: 0; }
.pref-text > label, .pref-text > .label { font-weight: 500; color: var(--ink); }
.pref-text > p { color: var(--ink-3); font-size: var(--fs-caption); }
.pref-control { display: grid; justify-items: end; gap: 6px; min-width: 0; }
.pref-control > select { width: 100%; }
@container page (max-width: 672px) {
    .pref-row { grid-template-columns: minmax(0, 1fr); padding: var(--s-3) var(--s-4); }
    .pref-control { justify-items: start; }
}
.kbd { display: inline-flex; align-items: center; height: 26px; padding: 0 8px; border: 1px solid var(--line-2); border-bottom-width: 2px; border-radius: 7px; background: var(--surface); color: var(--ink-2); font: 500 var(--fs-caption)/1 var(--font); }
/* A list with nothing in it yet: its tile, what would be here and why, and the way to the first one. */
.empty-state { display: grid; justify-items: center; gap: var(--s-3); padding: var(--s-6) var(--s-5); text-align: center; color: var(--ink-3); }
.empty-state > p { max-width: 34rem; }
.empty-state b { display: block; color: var(--ink); font-weight: 600; }
.empty-state > .product-tile { margin: 0; }
/* A setting that cannot be undone: its foot in the danger wash. */
.card.setting.danger { border-color: var(--neg-edge); }
.card.setting.danger .setting-foot { background: var(--neg-wash); color: var(--neg-ink); }
/* A long form's actions, in sight at the bottom while it is filled in (a role). */
.form-bar { position: sticky; bottom: var(--s-3); z-index: 2; display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--s-3) var(--s-5); padding: var(--s-3) var(--s-4); background: var(--raised); border: 1px solid var(--line-2); border-radius: var(--r-surface); box-shadow: var(--shadow-raised); }
/* A control the keyboard focuses stops above it: Firefox scrolls focus only just into view. */
html:has(.form-bar) { scroll-padding-bottom: calc(var(--h-control) + 2px + 3 * var(--s-3) + var(--s-4)); }
/* A choice of one as a row of segments (a role's level): the chosen one raised on the track. */
.segmented { display: inline-flex; flex-wrap: wrap; gap: 2px; padding: 3px; border: 1px solid var(--line); border-radius: var(--r-control); background: var(--surface-2); }
.segmented label { position: relative; display: inline-flex; align-items: center; height: 30px; padding: 0 12px; border-radius: 7px; color: var(--ink-2); font-size: var(--fs-caption); font-weight: 500; white-space: nowrap; cursor: pointer; }
.segmented label:hover { color: var(--ink); }
.segmented input { position: absolute; width: 1px; height: 1px; margin: 0; opacity: 0; }
/* The chosen one is ringed in the quiet ink, 5:1 and more against the track in both looks (WCAG 1.4.11). */
.segmented label:has(input:checked) { background: var(--surface); color: var(--ink); box-shadow: 0 0 0 1px var(--ink-3), var(--shadow-card); }
.segmented label:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 1px; }
.segmented-sm label { height: 26px; padding: 0 10px; }
/* A choice of one in a dialog (fieldset.choices: a role, a level): each option a card with its name over what it
   means, the chosen one in the accent - as a package's card. */
fieldset.choices .check { width: 100%; align-items: flex-start; padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--r-control); background: var(--surface); }
fieldset.choices .check:hover { border-color: var(--line-2); }
fieldset.choices .check:has(input:checked) { border-color: var(--accent-ink); background: var(--accent-wash); box-shadow: inset 0 0 0 1px var(--accent-ink); }
fieldset.choices .check:has(input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
fieldset.choices .check input { margin-top: 2px; accent-color: var(--accent-ink); }
fieldset.choices .check > span { display: flex; flex-direction: column; gap: 2px; }
fieldset.choices .check > span > .muted { line-height: 1.4; }
/* A table of people that stacks on a phone (table.stack-on-phone): the first cell - who - takes a line of its own,
   the rest share the line under it, so an address is never broken into pieces. */
@container page (max-width: 608px) {
    table.stack-on-phone thead { display: none; }
    table.stack-on-phone tr { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; column-gap: var(--s-2); padding: var(--s-2) 0; border-top: 1px solid var(--line); }
    table.stack-on-phone tbody tr:first-child { border-top: 0; }
    table.stack-on-phone td { padding: 4px var(--s-4); border-top: 0; }
    table.stack-on-phone td:first-child { grid-column: 1 / -1; }
    table.stack-on-phone td:empty { display: none; }
    table.stack-on-phone td.num { text-align: left; }
    .form-bar > span { display: none; }
    .form-bar { justify-content: flex-end; }
}

/* ── People (workspaces/people, projects/people) and the other lists of someone ───────────────────────────── */
.role-note { margin-left: var(--s-2); }
@media (max-width: 900px) { .role-note { display: none; } }

/* ── Workspace pages (workspaces/general, roles) ─────────────────────────────────────────────────────── */
/* An address waiting for its DNS: the two records to set, on a quiet panel under its name. */
.dns-records { margin-top: var(--s-3); padding: var(--s-3); border: 1px solid var(--line); border-radius: var(--r-control); background: var(--surface-2); }
.dns-records > p { margin-bottom: var(--s-2); color: var(--ink-3); font-size: var(--fs-caption); }
.dns-records table { background: var(--surface); border-radius: 8px; }
.dns-records th, .dns-records td { padding: 6px var(--s-3); }
/* A role's grants: a pill per product it opens, with that product's icon. */
.grant-list { display: flex; flex-wrap: wrap; gap: 6px; margin-top: var(--s-2); }
.grant { height: auto; min-height: 24px; padding: 3px 9px 3px 7px; white-space: normal; line-height: 1.3; }
.grant .product-icon { width: 14px; height: 14px; flex: none; color: var(--accent-ink); }
/* The built-in roles side by side. */
.role-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); gap: var(--s-3); }
.role-card { display: grid; justify-items: start; gap: var(--s-2); padding: var(--s-4); border: 1px solid var(--line); border-radius: var(--r-control); background: var(--surface-2); color: var(--ink-2); }
/* A role's form: a product a row - its tile, its name, its level - and what only some products have under them. */
.level-row { display: grid; grid-template-columns: 36px minmax(10rem, 1fr) auto; align-items: center; gap: var(--s-2) var(--s-4); padding: var(--s-3) var(--s-5); border-top: 1px solid var(--line); }
.level-row > .product-tile { width: 36px; height: 36px; margin: 0; }
.level-row > .product-tile .product-icon { width: 20px; height: 20px; }
.level-name { display: flex; flex-direction: column; gap: 2px; font-weight: 600; color: var(--ink); }
.level-name > .muted { font-weight: 400; }
.level-more { grid-column: 2 / -1; display: grid; gap: var(--s-2); }
.level-sub { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--s-2) var(--s-4); padding: var(--s-2) var(--s-3); border-radius: var(--r-control); background: var(--surface-2); }
.level-extra { width: 100%; align-items: flex-start; padding: var(--s-2) var(--s-3); border: 1px solid var(--line); border-radius: var(--r-control); }
.level-extra input { margin-top: 2px; }
.level-extra > span { display: flex; flex-direction: column; gap: 2px; }
.level-later { background: var(--surface-2); }
@media (max-width: 720px) {
    .level-row { grid-template-columns: 36px minmax(0, 1fr); padding: var(--s-3) var(--s-4); }
    .level-row > .segmented, .level-more { grid-column: 1 / -1; }
}

/* The workspace's projects: its letter, its name and slug, its products' doors taking the rest of the row. */
.issue-row.has-tile.project-row { grid-template-columns: 36px minmax(160px, 1fr) minmax(0, 2.5fr); align-items: center; }
@media (max-width: 720px) {
    .issue-row.has-tile.project-row { grid-template-columns: 36px minmax(0, 1fr); }
    .issue-row.has-tile.project-row > .project-doors { grid-column: 2; }
}
.ws-list-row { padding-top: var(--s-4); padding-bottom: var(--s-4); }
/* A new project: the products it will be in, by their icons, under its fields. */
.new-project-products { display: grid; gap: var(--s-2); padding: var(--s-3) var(--s-4); border-radius: var(--r-control); background: var(--surface-2); }

/* ── Account pages (access/preferences, security) ────────────────────────────────────────────────────── */
/* Security: where two-factor stands, as one line - the shield, what it is, its state. */
.security-state { display: grid; grid-template-columns: 44px minmax(0, 1fr) auto; align-items: center; gap: var(--s-4); }
.security-state > .product-tile { margin: 0; }
.security-state h2 { font-size: var(--fs-lead); }
/* On a page as narrow as a phone's, the state goes under the words. */
@container page (max-width: 608px) {
    .security-state { grid-template-columns: 44px minmax(0, 1fr); }
    .security-state > .badge { grid-column: 2; justify-self: start; }
}
.two-factor-setup { align-items: center; gap: var(--s-5); }

/* ── Administration (access/operators, audit) ────────────────────────────────────────────────────────── */
/* The audit log: a day a heading row, its events by the time of day under it. */
.audit td { padding-top: 8px; padding-bottom: 8px; }
.audit .day-row th { padding: 6px var(--s-5); border-top: 1px solid var(--line); background: var(--surface-2); color: var(--ink-2); font-size: var(--fs-caption); font-weight: 600; }
.audit .day-row th > span { margin-left: 4px; color: var(--ink-3); font-weight: 400; }
.audit tbody tr.day-row:hover { background: none; }
.audit-what { color: var(--ink); font-weight: 500; }
/* Who did it keeps their address whole: on a phone the table scrolls sideways rather than break it a letter a line
   (the kit's "anywhere" lets a table's column shrink to nothing). */
.audit .person-name, .audit .person-email { overflow-wrap: break-word; }
.audit-filter select { min-width: 9rem; }
.pagination.card-foot { display: flex; justify-content: flex-end; gap: var(--s-2); }

/* ── Project pages (projects/show, projects/people, projects/invitation): the project design session's section, 30.10.2026.
   Add project-page rules between this line and the billing section's line only. ── */
/* A project's head: its letter, as large as a workspace's mark on its General. */
.letter-tile.project-mark { width: 40px; height: 40px; border-radius: 10px; font-size: 18px; }
/* Its products (projects/show): a row each - the tile; the name and package, with the state and the "⋯" (or the room
   of one, so the states line up) on the right of that line; under them the limits and keys, drawn as the Subscription
   page's (.bill-limits), across the row; then what went wrong, with "Try again". */
.project-products { container-type: inline-size; }
.issue-row.has-tile.product-row { grid-template-columns: 36px minmax(0, 1fr) auto; grid-template-areas: 'tile head side' 'tile facts facts' 'tile error error'; align-items: center; row-gap: 0; }
.product-row > .product-tile { grid-area: tile; align-self: start; }
.product-row-head { grid-area: head; display: flex; align-items: center; flex-wrap: wrap; gap: 2px var(--s-2); min-width: 0; }
.issue-row.has-tile.product-row > .row-side { grid-area: side; justify-content: flex-end; }
.product-row > .bill-limits { grid-area: facts; }
.product-row > .product-error { grid-area: error; }
.product-error { display: grid; grid-template-columns: 13px minmax(0, 1fr); align-items: start; gap: var(--s-2) 8px; margin-top: var(--s-2); padding: 8px 10px; border: 1px solid var(--neg-edge); border-radius: var(--r-control); background: var(--neg-wash); color: var(--neg-ink); font-size: var(--fs-caption); line-height: 1.45; }
.product-error > .glyph { width: 13px; height: 13px; margin-top: 2px; }
.product-error > p { overflow-wrap: anywhere; }
.product-error > form { grid-column: 2; }
.product-error .glyph-cut { stroke: var(--neg-wash); }
.product-error .glyph-cut-fill { fill: var(--neg-wash); }
.row-menu-gap { flex: none; width: var(--h-sm); }
.products-callout { margin: 0 var(--s-5) var(--s-4); }
/* The products it has not, as chips by their icons on the sheet's quiet foot; an owner's lead to the Subscription page. */
.products-off { padding: var(--s-4) var(--s-5); border-top: 1px solid var(--line); background: var(--surface-2); }
.products-off-head { margin-bottom: var(--s-2); color: var(--ink-2); font-size: var(--fs-caption); font-weight: 600; }
.products-off-list { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 0; list-style: none; }
.product-chip { display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 10px 0 8px; border: 1px solid var(--line-2); border-radius: 8px; background: var(--surface); color: var(--ink-2); font-size: var(--fs-caption); font-weight: 500; line-height: 1; white-space: nowrap; text-decoration: none; }
.product-chip .product-icon { width: 15px; height: 15px; flex: none; color: var(--ink-3); }
a.product-chip:hover { border-color: var(--accent-ink); background: var(--accent-wash); color: var(--accent-ink); }
a.product-chip:hover .product-icon { color: var(--accent-ink); }
/* Its environments: the name, its badge, its "⋯". */
.environment-row { min-height: 52px; }
/* In a narrow sheet - beside two sidebars - the rows sit closer; on a phone the state and the "⋯" go under the name. */
@container (max-width: 600px) {
    .issue-row.has-tile.product-row { padding-inline: var(--s-4); }
    .products-off { padding: var(--s-3) var(--s-4); }
}
@container (max-width: 440px) {
    .issue-row.has-tile.product-row { grid-template-columns: 36px minmax(0, 1fr); grid-template-areas: 'tile head' 'tile side' 'tile facts' 'tile error'; }
    .issue-row.has-tile.product-row > .row-side { justify-content: flex-start; margin-top: 6px; }
    .product-row > .row-side > .row-menu-gap { display: none; }
}
@media (max-width: 640px) {
    .products-callout { margin: 0 var(--s-4) var(--s-3); }
}
/* Its people (projects/people): each one's role a pill that opens, quietly, what they open - in words, then a pill
   per product as a role's on the Roles page, and the products they have nothing in. An invitation's disc an outline. */
.opens > summary { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 4px var(--s-2); min-height: 32px; list-style: none; cursor: pointer; }
.opens > summary::-webkit-details-marker { display: none; }
.opens-toggle { display: inline-flex; align-items: center; gap: 2px; color: var(--ink-3); font-size: var(--fs-caption); white-space: nowrap; }
.opens-toggle svg { width: 14px; height: 14px; transition: transform 0.15s; }
.opens > summary:hover .opens-toggle, .opens[open] .opens-toggle { color: var(--ink-2); }
.opens[open] .opens-toggle svg { transform: rotate(180deg); }
.opens-body { display: grid; gap: var(--s-2); max-width: 36rem; margin: 4px 0 var(--s-1); padding: var(--s-3); border: 1px solid var(--line); border-radius: var(--r-control); background: var(--surface-2); color: var(--ink-2); font-size: var(--fs-caption); line-height: 1.45; }
.opens-body > .grant-list { margin-top: 0; }
.opens-none { color: var(--ink-3); }
tr:has(.opens[open]) > td { vertical-align: top; }
tbody tr:has(.opens[open]):hover { background: none; }
.role-line { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 4px var(--s-2); }
.person.is-invited > .avatar { border: 1px dashed var(--line-control); background: none; color: var(--ink-3); }
.accounts-line { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 4px var(--s-2); }
.accounts-line b { color: var(--ink); font-weight: 600; }
@container page (max-width: 608px) { table.stack-on-phone tr:has(.opens[open]) { align-items: start; } }
@media (prefers-reduced-motion: reduce) { .opens-toggle svg { transition: none; } }
/* An invitation (projects/invitation, a guest page): what it is to - the workspace's mark, the project, the role - and,
   under a line on the quiet tone, who asked and what the role means. The address it went to is shown, not typed. */
.invite-card { overflow: hidden; border: 1px solid var(--line); border-radius: var(--r-control); background: var(--surface); }
.invite-what { display: flex; align-items: center; gap: var(--s-3); padding: var(--s-3) var(--s-4); }
.invite-name { display: flex; flex: 1; flex-direction: column; min-width: 0; line-height: 1.35; }
.invite-name b { color: var(--ink); font-weight: 600; overflow-wrap: anywhere; }
.invite-name span { color: var(--ink-3); font-size: var(--fs-caption); }
.invite-words { padding: var(--s-3) var(--s-4); border-top: 1px solid var(--line); background: var(--surface-2); color: var(--ink-2); font-size: var(--fs-caption); line-height: 1.5; }
.invite-words b { color: var(--ink); font-weight: 600; }
.invite-join input[readonly] { background: var(--surface-2); color: var(--ink-2); }

/* ── Billing and buying (billing/billing, billing/start, done, pay): the billing design session's section, 30.10.2026.
   Everything above is the other design work's; add billing rules below this line only. ── */

/* The Billing page (billing/billing): where it stands is the Subscription page's .plan; who is billed, rows led by a
   tile; where the invoices go, a settings row of its own (.pref-row); then every invoice. */
/* The e-mail's box and its Save side by side, the box taking the room. */
.billing-email .pref-control { justify-items: stretch; }
.billing-email-field { display: flex; gap: var(--s-2); }
.billing-email-field input { flex: 1; min-width: 0; }
/* The invoices: the number and the day each on one line, the total right-aligned in figures of one width, the state a
   badge with its dates under it, then Pay and the PDF - a quiet link. */
.invoices .invoice-number, .invoices .invoice-date { white-space: nowrap; }
.invoices .invoice-number { color: var(--ink); }
.invoices .invoice-date { color: var(--ink-2); font-variant-numeric: tabular-nums; }
.invoices .invoice-total { color: var(--ink); font-weight: 600; }
.invoice-note { display: block; margin-top: 2px; color: var(--ink-3); font-size: var(--fs-caption); font-weight: 400; white-space: nowrap; }
.invoice-actions { width: 1%; }
.invoice-actions > * + * { margin-left: var(--s-3); }
.invoice-actions > .invoice-note { display: inline; margin-top: 0; }
.invoice-pdf { display: inline-flex; align-items: center; gap: 5px; vertical-align: middle; color: var(--ink-2); font-size: var(--fs-caption); font-weight: 500; text-decoration: none; }
.invoice-pdf:hover { color: var(--accent-ink); }
.invoice-pdf .product-icon { width: 15px; height: 15px; }
@media (max-width: 640px) {
    /* On a phone an invoice is a block: what it is for and its total, then its number, day and state, then Pay and the PDF. */
    table.invoices thead { display: none; }
    table.invoices tbody tr { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; grid-template-areas: 'for for total' 'number date state' 'actions actions actions'; align-items: center; gap: 4px var(--s-3); padding: var(--s-3) var(--s-4); border-top: 1px solid var(--line); }
    table.invoices td { padding: 0; border-top: 0; }
    table.invoices .invoice-for { grid-area: for; color: var(--ink); font-weight: 500; }
    table.invoices .invoice-total { grid-area: total; }
    table.invoices .invoice-number { grid-area: number; color: var(--ink-3); font-size: var(--fs-caption); }
    table.invoices .invoice-date { grid-area: date; color: var(--ink-3); font-size: var(--fs-caption); }
    table.invoices .invoice-state { grid-area: state; text-align: right; }
    table.invoices .invoice-actions { grid-area: actions; width: auto; text-align: left; }
}

/* Buying (billing/start): the products in the product list's groups, each a row that folds - its tile, its name and
   words, what is chosen for it - and opens to its package cards; how often to pay beside the heading; the key to the
   limits on one quiet line. */
.buy-head { display: flex; align-items: flex-end; justify-content: space-between; flex-wrap: wrap; gap: var(--s-3) var(--s-5); }
.buy-head p { margin-top: 2px; color: var(--ink-3); }
.buy-period { display: flex; align-items: center; gap: var(--s-3); }
.buy-period > .label { color: var(--ink-2); font-size: var(--fs-caption); font-weight: 500; }
.buy-products > .error { display: flex; align-items: center; gap: 6px; margin-top: var(--s-3); color: var(--neg-ink); font-size: var(--fs-caption); }
.kind-key { display: flex; flex-wrap: wrap; gap: 4px var(--s-4); margin: var(--s-4) 0 0; padding: 0; list-style: none; color: var(--ink-3); font-size: var(--fs-caption); }
.kind-key li { display: inline-flex; align-items: center; gap: 6px; }
.kind-key .product-icon { width: 14px; height: 14px; flex: none; }
.kind-key b { margin-right: 2px; color: var(--ink-2); font-weight: 600; }
.kind-note { margin-top: 2px; color: var(--ink-3); font-size: var(--fs-caption); }
.buy-group { margin-top: var(--s-5); }
.buy-group-head { display: flex; align-items: baseline; flex-wrap: wrap; gap: 2px var(--s-3); margin-bottom: var(--s-2); }
.buy-group-head h3 { color: var(--ink-2); font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; }
.buy-group-head p { color: var(--ink-3); font-size: var(--fs-caption); }
/* A product's row: the chevron, its tile (in the accent once a package is chosen), its name over its words, then the
   package chosen and its price - or what its packages start from. */
.pick + .pick { border-top: 1px solid var(--line); }
.pick > summary { list-style: none; }
.pick > summary::-webkit-details-marker { display: none; }
.pick-head { display: grid; grid-template-columns: 16px 36px minmax(0, 1fr) auto; align-items: center; gap: var(--s-3) var(--s-4); padding: var(--s-3) var(--s-5); cursor: pointer; user-select: none; }
.pick-head:hover { background: var(--surface-2); }
.pick-chevron { width: 16px; height: 16px; color: var(--ink-3); transform: rotate(-90deg); transition: transform 0.15s; }
.pick[open] .pick-chevron { transform: none; }
.pick-head > .product-tile { width: 36px; height: 36px; margin: 0; background: var(--surface-2); color: var(--ink-2); }
.pick-head > .product-tile .product-icon { width: 20px; height: 20px; }
.pick.is-chosen .pick-head > .product-tile { background: var(--accent-wash); color: var(--accent-ink); }
.pick-name { display: flex; flex-direction: column; min-width: 0; }
.pick-title { color: var(--ink); font-weight: 600; }
.pick-about { overflow: hidden; color: var(--ink-3); font-size: var(--fs-caption); text-overflow: ellipsis; white-space: nowrap; }
/* Who the product is for (Products::forLine), under its line: quieter still, never cut. */
.pick-for { color: var(--ink-3); font-size: var(--fs-caption); }
.pick-choice { display: flex; align-items: center; justify-content: flex-end; gap: var(--s-2); white-space: nowrap; }
.pick-choice [hidden] { display: none; }
.pick-price { color: var(--ink-3); font-size: var(--fs-caption); font-variant-numeric: tabular-nums; }
.pick.is-chosen .pick-price { color: var(--ink); font-size: var(--fs-body); font-weight: 600; }
/* Opened: the package cards on a quieter tone, under a hairline. */
.pick-body { min-width: 0; margin: 0; padding: var(--s-4) var(--s-5) var(--s-5); border: 0; border-top: 1px solid var(--line); background: var(--surface-2); }
.pick-body .package-options { margin-top: 0; }
@media (prefers-reduced-motion: reduce) { .pick-chevron { transition: none; } }
/* The Project and Billed to cards (03.11.2026, the owner: "solid and logical"): six columns in the form's 60rem, each
   field as wide as what goes in it - a postal code a third, a street the whole line -, so the rows line up card to card;
   two columns on a narrow page and one on a phone. A group's head ("Address") is a hairline and a quiet title across. */
.fields.buy-grid { grid-template-columns: repeat(6, minmax(0, 1fr)); }
.buy-grid > .span-2 { grid-column: span 2; }
.buy-grid > .span-3 { grid-column: span 3; }
.buy-grid > .span-4 { grid-column: span 4; }
.buy-grid > .span-6 { grid-column: 1 / -1; }
.buy-grid > .buy-grid-head { grid-column: 1 / -1; grid-row: auto; margin-top: var(--s-2); padding-top: var(--s-4); border-top: 1px solid var(--line); color: var(--ink-2); font-size: var(--fs-body); font-weight: 600; }
.buy-grid > .field > .segmented { justify-self: start; }
@container page (max-width: 608px) {
    .fields.buy-grid { grid-template-columns: minmax(0, 1fr); }
    .buy-grid > .span-2, .buy-grid > .span-3, .buy-grid > .span-4 { grid-column: 1 / -1; }
}
/* The address's second line, folded under the street until asked for (app.js): a quiet link close under the street. */
.buy-grid > .buy-more { grid-column: 1 / -1; grid-row: auto; margin-top: calc(-1 * var(--s-3)); }
.buy-more[hidden], .buy-line2[hidden] { display: none; }
.buy-more > button { padding: 0; border: 0; background: none; color: var(--accent-ink); font: inherit; font-size: var(--fs-caption); font-weight: 500; cursor: pointer; }
.buy-more > button:hover { text-decoration: underline; }
.buy-more > button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }
/* A new workspace's name and address in a box of their own under the choice, only while "A new workspace" is chosen.
   The box reaches out by its padding, so its fields stand in the card's columns. */
.buy-inset { grid-column: 1 / -1; grid-row: auto; min-width: 0; margin: 0 calc(-1 * var(--s-4) - 1px); padding: var(--s-4); border: 1px solid var(--line); border-radius: var(--r-control); background: var(--surface-2); }
.buy-inset > legend { float: left; width: 100%; margin-bottom: var(--s-3); padding: 0; font-weight: 600; }
.buy-inset > .fields { clear: both; }
form[data-purchase]:has(#workspace option[value="new"]:not(:checked)) .buy-new-workspace { display: none; }
form[data-purchase]:has(input[name="billed_as"][value="person"]:checked) .buy-company { display: none; }
form[data-purchase]:has(input[name="billed_as"][value="company"]:checked) .buy-person { display: none; }
/* An address's box with what comes before it written in front, quiet (services.my-beast.com/acme/ then the slug): one
   control, so the line reads as the address it makes. A long front is cut at its start, its end kept in sight. */
.affix { display: flex; align-items: center; height: var(--h-control); border: 1px solid var(--line-control); border-radius: var(--r-control); background: var(--surface); cursor: text; }
.affix:has(> input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 0; border-color: var(--accent); }
.affix:has(> input[aria-invalid='true']) { border-color: var(--neg-edge); }
.affix > .affix-text { flex: 0 1 auto; min-width: 0; max-width: 65%; padding-left: 12px; overflow: hidden; color: var(--ink-3); font-family: var(--mono); font-size: 0.92em; letter-spacing: 0.04em; white-space: nowrap; text-overflow: ellipsis; direction: rtl; }
.affix > .affix-text > bdi { direction: ltr; }
.affix > input[type='text'] { flex: 1 1 6rem; min-width: 6rem; height: 100%; padding-left: 0; border: 0; background: transparent; }
.affix > input[type='text']:focus-visible { outline: none; }
/* What still needs a look, over the total, once sending was tried. */
.purchase-check { display: flex; flex: 1 1 100%; align-items: center; gap: 6px; margin: 0; color: var(--neg-ink); font-size: var(--fs-caption); font-weight: 500; }
.purchase-check[hidden] { display: none; }
.purchase-total.is-error { color: var(--neg-ink); }
.purchase-actions { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-left: auto; }
.purchase-actions > [hidden] { display: none; }
/* The steps (03.11.2026, the owner: products, then the project, then who is billed, then payment): a numbered row over
   the form. The step you are on is the primary's colour, one done the accent's wash, one not reached yet quiet and
   closed; on a phone only the step you are on keeps its name. */
.steps[hidden] { display: none; }
.steps ol { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-1) var(--s-2); margin: 0; padding: 0; list-style: none; }
.steps li { display: flex; align-items: center; gap: var(--s-2); }
.steps li + li::before { content: ''; width: 24px; height: 1px; background: var(--line-2); }
.step-link { display: inline-flex; align-items: center; gap: var(--s-2); height: 32px; padding: 0 12px 0 4px; border: 0; border-radius: 999px; background: none; color: var(--ink-2); font: inherit; font-weight: 500; cursor: pointer; }
.step-link:hover:not(:disabled) { background: var(--surface-2); color: var(--ink); }
.step-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.step-link:disabled { color: var(--ink-3); cursor: default; }
.step-number { display: grid; place-items: center; width: 24px; height: 24px; border: 1px solid var(--line-2); border-radius: 50%; font-size: var(--fs-caption); font-variant-numeric: tabular-nums; }
.step-link.is-done .step-number { border-color: transparent; background: var(--accent-wash); color: var(--accent-ink); }
.step-link[aria-current='step'] { color: var(--ink); font-weight: 600; }
.step-link[aria-current='step'] .step-number { border-color: transparent; background: var(--primary); color: var(--on-primary); }
.buy-step[hidden] { display: none; }
/* A step's heading takes the focus when the step opens, for a screen reader to start there: no ring for that. */
.buy-step h2[tabindex='-1']:focus { outline: none; }
@container page (max-width: 608px) {
    .steps li + li::before { width: 10px; }
    .step-link:not([aria-current='step']) .step-label { display: none; }
    .step-link:not([aria-current='step']) { padding-right: 4px; }
}
/* The review: the products' prices, then the project, its accounts and who is billed - a title, its lines (the first
   plain, the rest quieter) and Change, which goes back to that step. */
.review-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); padding: var(--s-4) var(--s-5) var(--s-2); }
.review-head h3, .review-part h3 { font-size: var(--fs-body); font-weight: 600; }
.review-part { display: grid; grid-template-columns: 10rem minmax(0, 1fr) auto; align-items: start; gap: var(--s-1) var(--s-4); padding: var(--s-4) var(--s-5); border-top: 1px solid var(--line); }
/* The title and the first line stand level with Change's middle. */
.review-part > h3 { display: flex; align-items: center; min-height: var(--h-sm); }
.review-lines { display: grid; gap: 2px; margin: calc((var(--h-sm) - 1lh) / 2) 0 0; min-width: 0; overflow-wrap: anywhere; }
.review-lines > span + span { color: var(--ink-3); font-size: var(--fs-caption); }
[data-review][hidden] { display: none; }
/* /start's review in two columns (03.11.2026, the owner): the products and their prices on the left, wider; the project,
   its accounts and who is billed on the right, each its title and Change over its lines, and under them a quieter sheet
   with the link for someone else to pay. One under the other on a narrow page. */
.review-columns { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); align-items: start; gap: var(--s-5); margin-top: var(--s-4); }
.review-side { display: grid; gap: var(--s-4); }
.review-side .review-part { grid-template-columns: minmax(0, 1fr) auto; }
.review-side .review-part:first-child { border-top: 0; }
.review-side .review-lines { grid-column: 1 / -1; grid-row: 2; margin-top: 0; }
/* The basket back (billing/start, BasketService): a quiet line over the steps - its mark, what is kept, Start over. */
.basket-back { display: flex; align-items: center; gap: var(--s-3); margin-bottom: var(--s-4); padding: var(--s-3) var(--s-3) var(--s-3) var(--s-4); border: 1px solid var(--line); border-radius: 12px; background: var(--surface); }
.basket-back-mark { display: grid; place-items: center; flex: none; width: 30px; height: 30px; border-radius: 9px; background: var(--surface-2); color: var(--ink-2); }
.basket-back p { flex: 1 1 auto; min-width: 0; color: var(--ink-3); font-size: var(--fs-caption); }
.basket-back p b { color: var(--ink); font-weight: 600; }
.basket-back form { flex: none; }
@container page (max-width: 608px) {
    .basket-back { flex-wrap: wrap; }
    .basket-back p { flex-basis: calc(100% - 30px - var(--s-3)); }
}
/* Someone else pays (billing/start, [data-share]): a share mark beside the question; once asked, the link in a box with
   Copy (and Share where the device shares), when it runs out and their page; a changed order says so and asks again. */
.review-share { display: grid; justify-items: start; gap: var(--s-3); padding: var(--s-4) var(--s-5); background: var(--surface-2); box-shadow: none; }
.review-share-head { display: grid; grid-template-columns: auto minmax(0, 1fr); align-items: start; gap: var(--s-3); width: 100%; }
.review-share-mark { display: grid; place-items: center; width: 34px; height: 34px; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); color: var(--ink-2); }
.review-share-mark svg { width: 16px; height: 16px; }
.review-share-words { display: grid; gap: 2px; padding-top: 1px; }
.review-share h3 { font-size: var(--fs-body); font-weight: 600; }
.review-share p { color: var(--ink-3); }
.review-share-made { display: grid; gap: var(--s-2); width: 100%; }
.review-share-made[hidden], .review-share [hidden] { display: none; }
.review-share-row { display: flex; gap: var(--s-2); width: 100%; }
.review-share-row > input { flex: 1 1 auto; min-width: 0; height: var(--h-sm); padding-inline: var(--s-3); font-size: var(--fs-caption); letter-spacing: 0; color: var(--ink-2); background: var(--surface); text-overflow: ellipsis; }
.review-share-row > .btn { flex: none; }
.review-share-copy { min-width: 5.5rem; }
.review-share-note { display: flex; flex-wrap: wrap; gap: 4px var(--s-3); font-size: var(--fs-caption); }
.review-share-note b { color: var(--ink-2); font-weight: 600; }
.review-share-note a { display: inline-flex; align-items: center; gap: 4px; }
.review-share-stale, .review-share-error { display: flex; align-items: flex-start; gap: 6px; font-size: var(--fs-caption); }
.review-share-stale svg, .review-share-error svg { flex: none; margin-top: 2px; }
.review-share-stale { color: var(--ink-2) !important; }
.review-share-stale svg { color: var(--orange, currentColor); }
.review-share-error { color: var(--neg-ink) !important; }
.review-share.is-stale .review-share-row > input { text-decoration: line-through; color: var(--ink-3); }
@container page (max-width: 900px) {
    .review-columns { grid-template-columns: minmax(0, 1fr); }
}
/* A shared purchase's page (billing/shared): read by someone who may not know ours, so a column, not the window. */
.shared-page { width: 100%; max-width: 52rem; margin-inline: auto; }
/* A shared purchase's link, for its buyer (billing/shared): the address in a box as wide as the card allows, Copy beside. */
.share-link-row { display: flex; gap: var(--s-2); max-width: 60rem; }
.share-link-row > input[type='text'] { flex: 1 1 auto; min-width: 0; color: var(--ink-2); }
.share-link-change { margin-top: var(--s-3); color: var(--ink-3); font-size: var(--fs-caption); }
@container page (max-width: 608px) {
    .review-head, .review-part, .review-share { padding-inline: var(--s-4); }
    .review-part { grid-template-columns: minmax(0, 1fr) auto; }
    .review-part > .review-lines { grid-column: 1 / -1; grid-row: 2; margin-top: 0; }
}
@media (max-width: 640px) {
    .pick-head { grid-template-columns: 16px 32px minmax(0, 1fr); gap: 2px var(--s-3); padding: var(--s-3) var(--s-4); }
    .pick-chevron, .pick-head > .product-tile { grid-row: span 2; }
    .pick-head > .product-tile { width: 32px; height: 32px; }
    .pick-choice { grid-column: 3; justify-content: flex-start; }
    .pick-body { padding: var(--s-3) var(--s-4) var(--s-4); }
}
/* On a phone an invoice without a PDF (a test one) has nothing under it to press: no line for it. */
@media (max-width: 640px) { table.invoices .invoice-actions:not(:has(a)) { display: none; } }

/* The test payment (billing/pay): the purchase's lines as the Subscription page's, the total under them, and a foot with
   what paying does on the left, Cancel and Pay on the right. */
.pay-each { display: block; color: var(--ink-3); font-size: var(--fs-caption); }
.pay-total { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-3); padding: var(--s-4) var(--s-5); border-top: 1px solid var(--line-2); font-weight: 600; }
.pay-foot { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s-2) var(--s-3); padding: var(--s-3) var(--s-5); border-top: 1px solid var(--line); background: var(--surface-2); color: var(--ink-3); font-size: var(--fs-caption); }
.pay-foot > span { margin-right: auto; }
@media (max-width: 720px) { .pay-total, .pay-foot { padding-inline: var(--s-4); } }

/* Back from paying (billing/done): where the purchase stands, as one sheet - a mark, what is happening, what to do. */
.await { display: grid; grid-template-columns: 44px minmax(0, 1fr) auto; align-items: center; gap: var(--s-4); }
.await h2 { font-size: var(--fs-lead); }
.await p { margin-top: 2px; color: var(--ink-3); }
.await-mark { display: grid; place-items: center; width: 44px; height: 44px; border-radius: var(--r-control); background: var(--surface-2); color: var(--ink-3); }
.await-mark .glyph { width: 20px; height: 20px; }
.await.is-neg { border-color: var(--neg-edge); }
.await.is-neg .await-mark { background: var(--neg-wash); color: var(--neg-ink); }
/* While it waits, a ring that turns - a still dotted one when motion is turned down. */
.await-mark.is-busy { background: var(--accent-wash); }
.await-mark.is-busy::after { content: ''; width: 20px; height: 20px; border: 2px solid var(--accent-ink); border-right-color: transparent; border-radius: 50%; animation: await-turn 0.9s linear infinite; }
@keyframes await-turn { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .await-mark.is-busy::after { animation: none; border-style: dotted; border-right-color: var(--accent-ink); } }
@media (max-width: 640px) {
    .await { grid-template-columns: 44px minmax(0, 1fr); }
    .await > .btn { grid-column: 2; justify-self: start; }
}
/* The invoices' cells closer together than a table's, the first and last keeping the sheet's edge. */
@media (min-width: 641px) {
    .invoices :is(th, td) { padding-left: var(--s-3); padding-right: var(--s-3); }
    .invoices :is(th, td):first-child { padding-left: var(--s-5); }
    .invoices :is(th, td):last-child { padding-right: var(--s-5); }
}
/* On a phone the total's bar stays small: the total in body type over a button as wide as the bar. */
@media (max-width: 640px) {
    form[data-purchase] .purchase-bar { bottom: var(--s-2); gap: var(--s-2); padding: var(--s-2) var(--s-3); }
    form[data-purchase] .purchase-total { flex: 1 1 100%; font-size: var(--fs-body); }
    form[data-purchase] .purchase-actions { flex: 1 1 100%; }
    form[data-purchase] .purchase-actions > .btn { flex: 1 1 0; height: var(--h-sm); }
}
/* The sign-up and forgot-password forms' field for scripts (components/honeypot): out of sight and out of reach. */
.hp { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }
