/* BlueShop marketing — what is particular to the public pages.

   The page furniture they share with the shop (the reset, the column, the brand, the
   language switch, the footer) lives in /shared/chrome.css and is loaded before this.
   What is left here is the argument the marketing pages make and the shop does not: the
   radial build. A fusion machine is described as a sequence of layers outward from the
   plasma, and this product's tiers are literally nested capability sets, so the page
   draws them as the shells they are. Everything else stays quiet — one bright color (the
   plasma), one monospaced voice for labels and figures, and prose in the sans.

   Guardrail: everything self-hosted — no webfonts, no CDN. Colors and type come from
   /shared/tokens.css, the one palette file.

   Load order: tokens → chrome → this. */

/* Prose spans the column — the same width as the rules above it and the screenshots
   below it — and it is set justified.

   The two decisions hold each other up. Paragraphs used to stop at 32, 34, 38 and
   42rem: four defensible numbers that together made every block look stunted by a
   different amount, each against furniture that ran the full 58rem. Letting them run
   the column ends that, at the cost of a long line — about a hundred characters, well
   past the textbook 75.

   Two things pay that cost back, and the second is why the first is affordable.

   `hyphens: auto` with the `lang` attribute every page carries lets the browser break
   inside words using its own patterns for that language — which matters most in German,
   where one *Auftragsverarbeitungsvertrag* on a line would otherwise stretch everything
   around it. Measured, not assumed: it is **not universal**. Firefox and Safari ship
   hyphenation dictionaries; Chromium on Linux fetches them through its component
   updater and silently does nothing without them, which is the case in the build these
   pages were checked in. So this is an improvement where it lands, never a load-bearing
   assumption.

   What carries the weight is the long measure itself. Rivers of white are a
   *narrow*-column problem: the slack a justified line has to absorb is spread across
   its word gaps, and a hundred-character line has some fifteen of them to share it
   between. The same slack in a 32rem column would land in five. Wide and justified is
   a pairing; either alone would be worse.

   Three things stay out of it, each for that same reason or worse. The definition
   lists sit in a 42rem grid column — justifying them was tried and gives back exactly
   the rivers the paragraphs avoid, so a list reads ragged and a paragraph reads
   justified, which is the honest difference between them. `.actions` is a paragraph of
   *buttons* and would have its links flung to both margins. And the hero lede is a
   column beside the cross-section, not a full-width one. */
.page-head .lede,
.facts p,
.institutes p,
.legal p,
.legal .notice,
.close p,
.assurance p,
.exchange .turn p {
  text-align: justify;
  -webkit-hyphens: auto;
  hyphens: auto;
  /* Where hyphenation does run: no breaking a word shorter than six letters, and never
     leaving fewer than three on either side of the break. Without it the browser is
     entitled to strand "ei-" at a line end, which costs more than the gap it saved. */
  -webkit-hyphenate-limit-before: 3;
  -webkit-hyphenate-limit-after: 3;
  hyphenate-limit-chars: 6 3 3;
}

/* ── chrome, the part that is ours ───────────────────────────────────────────── */

/* Five entries plus the language switch. They may break into a second right-aligned
   row on a narrow screen; what they may not do is break *inside* an entry — "FOR
   INSTITUTES" split over two lines reads as two entries. */
.top nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: .4rem 1.5rem;
  align-items: baseline;
}
.top nav a {
  font-family: var(--font-display);
  font-size: .8rem;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
  text-decoration: none;
  white-space: nowrap;
}
.top nav a:hover, .top nav a[aria-current] { color: var(--ink); }
/* The disclosure itself is shared furniture (chrome.css); what is ours is how the
   three links inside it read — the same muted-until-current voice as the nav entries
   beside them, which is why they belong here and not four hundred lines down among
   the legal pages, where they had drifted to. */
.langs a { color: var(--muted); }
.langs a:hover, .langs a[aria-current] { color: var(--ink); }
/* Named for the place, not for the act: a static page cannot know whether you are
   signed in, and "Sign in" sent a signed-in reader to their own account under a label
   that promised something else. "Account" is true in both states and needs no session,
   no request and no JavaScript to be right. */
.top nav .signin { color: var(--accent); }

/* ── hero ────────────────────────────────────────────────────────────────────── */

/* The figure column is the width of the figure — it used to be 20rem holding a 17rem
   drawing pushed to the right, so three of them were empty and the text column paid
   for them. */
.hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 17rem);
  gap: 3rem;
  align-items: center;
  padding: 3.5rem 0 3rem;
}

h1 {
  font-family: var(--font-display);
  font-size: clamp(2rem, 5vw, 2.8rem);
  font-weight: 700;
  letter-spacing: -.045em;
  line-height: .98;
  margin: 0 0 1.2rem;
}

/* The hero headline is two voices, not one. Three lines of equal weight arrive as a
   wall and the eye has to read all of it before any of it means anything; a wordmark
   with a sentence under it is read in order — who, then what.

   Blue and not plasma, deliberately. `--plasma` is the palette's single saturated
   color and it is already spent on this page, on the core of the cross-section a hand's
   width to the right. A magenta wordmark would take that away from the figure and leave
   the page with two things shouting. Blue is what the brand is named after anyway. */
.hero h1 { margin: 0 0 1.4rem; }

.hero h1 .wordmark {
  display: block;
  font-size: clamp(2.6rem, 7vw, 4.2rem);
  line-height: 1;
  color: var(--accent);
}

/* Sized by its longest translation. The French line is the longest at thirty-seven
   characters, and monospaced type is wide: at the ceiling below it still ends inside the
   text column and leaves the cross-section beside it, which is what the old headline had
   stopped doing. Text weight, not bold — the size difference alone would still read as
   one shouted block. */
.hero h1 .tagline {
  display: block;
  margin-top: .6rem;
  font-size: clamp(1.05rem, 2.4vw, 1.45rem);
  font-weight: 400;
  letter-spacing: -.01em;
  line-height: 1.3;
  color: var(--ink);
}

/* No cap. The hero's grid already gives the lede its width — the column beside the
   cross-section — and a second limit inside that column only stopped it three rem
   short of the boundary it could not have crossed anyway.

   Ragged right rather than justified, and it is the one place on these pages where
   that is the better setting: at 38rem this is the narrowest running text on the site,
   and it is the largest — 1.15rem — so a justified line here has the fewest word gaps
   to spread its slack across. Wide-and-justified is a pairing (see the top of this
   file); this column is not wide. */
.lede { font-size: 1.15rem; margin: 0 0 2rem; }

/* `.actions`, `.cta` and `.cta-quiet` moved to /shared/chrome.css (2026-09-06): the
   account page has a call to action too and loads that sheet, not this one. */

/* The cross-section. Steel lines, one hot core, and a dashed cut that points at the
   section below — the figure is an argument, not an ornament. */
.poloidal { margin: 0; justify-self: end; max-width: 17rem; }
.poloidal svg { width: 100%; height: auto; display: block; overflow: visible; }
.flux path {
  fill: none;
  stroke: var(--shell-3);
  stroke-width: .7;
}
.flux .sep { stroke: var(--shell-1); stroke-width: 1.1; }
.flux .core { stroke: var(--plasma); stroke-width: 1.4; fill: var(--plasma); fill-opacity: .12; }
.cut { stroke: var(--muted); stroke-width: .6; stroke-dasharray: 2.5 2.5; }
.axis { fill: var(--plasma); }

.poloidal figcaption {
  font-family: var(--font-display);
  font-size: .7rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
  text-align: right;
  margin-top: .75rem;
}

/* ── section furniture ───────────────────────────────────────────────────────── */

.eyebrow {
  font-family: var(--font-display);
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 1.75rem;
  padding-bottom: .6rem;
  border-bottom: 1px solid var(--line-strong);
}

.build, .facts, .close, .page-head { padding: 2.75rem 0; }
.build { padding-top: 0; }

/* ── the product, shown ──────────────────────────────────────────────────────── */

/* Real screenshots, one per page at most. A plain border and a caption — no drawn
   browser chrome, because a mockup frame around a real product reads as a product
   that does not exist yet. The dark UI sits on the light page deliberately: it is
   a window into the other surface, not part of this one. */
.shot { margin: 0 0 2.75rem; }
.shot img {
  width: 100%;
  height: auto;
  display: block;
  border: 1px solid var(--line-strong);
}
.shot figcaption, .runs figcaption {
  margin-top: .6rem;
  font-family: var(--font-display);
  font-size: .75rem;
  letter-spacing: .04em;
  color: var(--muted);
}
section .shot { margin: 1.5rem 0 0; }

/* ── where it runs ───────────────────────────────────────────────────────────── */

/* The trust question as a picture: the browser, our machines, the sealed tenants, and
   the one dashed line that ever leaves — a message and its context, to Anthropic, for
   the reply. Same line language as the cross-section, and the same pink ellipse, now
   inside the tenant: the plasma is where your design is.

   The label says EU rather than Germany on purpose. Mail already routes through
   Scaleway in France, and backups or compute may follow; a page that names one country
   becomes wrong the day either does, and this one is read as a promise.

   Decoration for the definition list beside it, which states every one of these facts
   in words — hence aria-hidden, and hidden entirely on narrow screens rather than
   scaled into illegibility. */
.runs { margin: 1.5rem 0 2rem; }
.runs svg { width: 100%; height: auto; display: block; }
.runs .frame { fill: none; stroke: var(--line-strong); stroke-width: 1.5; }
.runs .server { fill: none; stroke: var(--ink); stroke-width: 2; }
.runs .yours { fill: none; stroke: var(--accent); stroke-width: 2; }
.runs .wire { stroke: var(--ink); stroke-width: 1.5; }
.runs .leaves { fill: none; stroke: var(--muted); stroke-width: 1.5; stroke-dasharray: 5 5; }
.runs .design { fill: var(--plasma); }
.runs text {
  font-family: var(--font-display);
  font-size: 12px;
  letter-spacing: .04em;
  fill: var(--ink);
}
.runs .small { font-size: 10px; letter-spacing: .02em; fill: var(--muted); }
.runs .yours-label { fill: var(--accent); }

/* ── the two arguments ───────────────────────────────────────────────────────── */

/* Why hosted, told once per half of the audience: the course that cannot spend week
   one on installs, and the group whose installation is one person's machine. Side by
   side because a reader is one of the two and picks their column. The note under them
   holds the sentence this site must not bury: Bluemira itself stays free — sold here
   is the machine it runs on, not the software. */
.paths {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 3rem;
  padding: 0 0 2.75rem;
}
.paths .path h2 {
  font-family: var(--font-display);
  font-size: .95rem;
  font-weight: 700;
  letter-spacing: -.02em;
  margin: 0 0 .6rem;
}
.paths .path p { margin: 0; }
.paths .path-more { margin: .9rem 0 0; }
.paths .note { grid-column: 1 / -1; }

/* One exchange from a real session, typeset rather than screenshotted: readable at
   any size, translatable, and it weighs nothing. The accent bar marks the agent's
   voice — the same accent that marks commitments elsewhere on the site. */
.exchange { margin: 1.5rem 0 0; }
.exchange .turn {
  margin: 0 0 1rem;
  padding: 1.1rem 1.4rem;
  background: var(--card);
}
.exchange .agent { border-left: 3px solid var(--accent); }
.exchange .turn p { margin: 0 0 .8rem; }
.exchange .turn p:last-child { margin-bottom: 0; }
.exchange figcaption {
  font-family: var(--font-display);
  font-size: .75rem;
  letter-spacing: .04em;
  color: var(--muted);
}

/* ── the build ───────────────────────────────────────────────────────────────── */

.shells { list-style: none; margin: 0; padding: 0; }

.shells > li {
  display: grid;
  /* A definite track for the bar rather than minmax(0, …), so the segments' widths
     resolve against a size that is settled before they are laid out. Robustness, not
     a fix: the collapse this looked like it was curing turned out to be the CSP
     blocking the inline styles (see .bar i), and a mutation back to minmax() still
     renders fine. Left definite because % against an auto track is a footgun worth
     not carrying, but nothing here depends on it. */
  grid-template-columns: 11rem 17rem minmax(0, 1fr);
  gap: 0 2rem;
  align-items: baseline;
  padding: 1.1rem 0;
  border-top: 1px solid var(--line);
}
.shells > li:first-child { border-top: 0; }

.tier {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: .95rem;
  letter-spacing: -.02em;
}

/* Segments accumulate left to right: each tier draws its own shell plus every shell
   inside it, so containment is visible rather than claimed. */
.bar { display: flex; gap: 2px; align-self: start; margin-top: .3rem; height: .85rem; }
/* Widths live here and not on the elements. Our CSP is `default-src 'self'` with no
   style-src of its own, so it falls back to that — and that forbids the style=""
   attribute outright. A `style="--w:26%"` on each segment silently did nothing and
   the whole signature rendered as empty space. The guardrail is right; the markup
   was wrong, and a shell's thickness is a constant of the design anyway. */
.bar i { display: block; transform-origin: left center; }
.bar .s1 { width: 26%; background: var(--plasma); }
.bar .s2 { width: 30%; background: var(--shell-1); }
.bar .s3 { width: 26%; background: var(--shell-2); }
.bar .add {
  width: 42%;
  background: repeating-linear-gradient(
    -45deg, var(--shell-2) 0 2px, transparent 2px 5px
  );
  box-shadow: inset 0 0 0 1px var(--shell-2);
}

/* Credit is not a shell, so its mark must not read as one. A shell segment is solid
   and sits at a fixed width because a tier is a fixed thing; this is a gauge, drawn
   full and fading out, because what it measures is a quantity that runs down. The
   fade is the whole idea: it is the only mark on this list that is not a boundary. */
.bar .fuel {
  width: 82%;
  background: linear-gradient(
    to right, var(--plasma) 0%, var(--shell-1) 55%, transparent 100%
  );
}

.what { color: var(--muted); font-size: .95rem; }
.addon .tier { color: var(--muted); }
/* Same weight as the add-on's: neither is a tier, and the eye should find the three
   shells first. */
.credit .tier { color: var(--muted); }

/* The shells are where a reader compares the tiers, so it is where the way to buy
   one belongs. `.actions` sets margin: 0 for the hero, where a heading above it
   supplies the space; here it follows a note and has to make its own. */
.build .actions { margin-top: 1.75rem; }

.note {
  font-size: .9rem;
  color: var(--muted);
  margin: 1.5rem 0 0;
  padding-left: 1rem;
  border-left: 2px solid var(--plasma);
}

/* ── the plans table (the same shells, carrying detail) ──────────────────────── */

/* Wider label column than the front page's: the catalogue uses BlueAgent's own
   display names, and the add-on's is a phrase rather than a word. Two names for
   one product is drift a customer sees before we do, so the page takes the
   canonical one and the layout gives way — a test holds the two together. */
/* Three columns, not four: the shell bar moves under the name it belongs to.

   The price cell now carries the rates *and* an order form — a number field beside a
   button, and "Commander" is the longest of the three — so it needs a good twelve rem.
   Taking that out of a fourth column left the bar a stub, which is the one thing on
   this page that may not shrink: it is the radial build, the argument the whole design
   is built on. Under the tier name it has the room it needs and is tied to its plan by
   position rather than by row alignment, which is the better relationship anyway.

   The cells are placed explicitly because the markup order — tier, bar, price, what —
   is the reading order and should stay that way in the source. */
.plans > li { grid-template-columns: 13rem 10rem 9rem minmax(0, 1fr); }

/* The plans page is the order page: a quantity per row, one button, one basket. A
   plain GET form and no JavaScript — it submits to `/checkout/?lang=…&learner=10&…`,
   which means the **query string is the basket**. Nothing is stored, so nothing can be
   lost between here and a session, and the resulting address is shareable: an institute
   buyer can send exactly the order they are proposing to whoever has to approve it.

   It cannot reach a payment. Between here and a provider stand a session, a confirmed
   address, the group's name on a first purchase and the terms — all on the checkout,
   which is the page this one hands over to. */
.qty {
  display: block;
  margin-top: .8rem;
  font-family: var(--font-display);
  font-size: .7rem;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
}
.qty input {
  display: block;
  width: 4.4rem;
  margin-top: .3rem;
  padding: .4rem .5rem;
  font: inherit;
  font-size: .9rem;
  border: 1px solid var(--line-strong);
  background: var(--card);
  color: var(--ink);
}
/* Zero reads as "not ordering this", so it is drawn as one — the row a customer has
   actually put a number in should be the one their eye lands on. */
.qty input:not([value="0"]), .qty input:focus { border-color: var(--accent); }

.basket-go { margin: 1.75rem 0 0; }
.basket-go button {
  font-family: var(--font-display);
  font-size: .9rem;
  letter-spacing: .01em;
  padding: .7rem 1.3rem;
  border: 0;
  background: var(--accent);
  color: var(--on-accent);
  cursor: pointer;
}
.basket-go button:hover { background: var(--ink); }

.price {
  font-family: var(--font-display);
  font-size: .82rem;
  letter-spacing: .02em;
  color: var(--muted);
  align-self: start;
  margin-top: .1rem;
}
/* The number is the fact; the cadence around it is furniture. Ink for the monthly
   figure, and the yearly line stays quiet under it. */
.price strong { font-size: .95rem; color: var(--ink); }

.plans .what ul { margin: 0; padding: 0; list-style: none; }
.plans .what li { margin: .2rem 0; padding-left: .9rem; text-indent: -.9rem; }
.plans .what li::before { content: "+ "; color: var(--line-strong); }
/* A shell's first line names what it contains, which is a different kind of statement
   from the ones under it — hence ⊃, the notation this audience reads fluently. NOT on
   the add-on: PROCESS contains nothing, it sits beside the stack, and a symbol that
   says otherwise would be exactly the decoration this design is trying not to be. */
.plans .shells > li:not(.addon) .what li:first-child::before {
  content: "⊃ ";
  color: var(--shell-2);
}

/* ── the assurance ───────────────────────────────────────────────────────────── */

/* The sentence a budget holder needs before any feature list: spending here has a
   hard ceiling. A card rather than prose, so it reads as a commitment and not as a
   remark — and accent rather than plasma, because trust is the brand's colour and
   the plasma is spent where the heat is. */
.assurance {
  background: var(--card);
  border-left: 3px solid var(--accent);
  padding: 1.6rem 2rem;
  margin: 2.75rem 0;
}
.assurance p { margin: 0; }

/* ── facts ───────────────────────────────────────────────────────────────────── */

/* Shared with the Impressum, which is the same shape of thing: a label and the fact
   under it. One rule rather than two, so the two pages cannot drift apart. */
.facts dl, .legal dl {
  display: grid;
  grid-template-columns: 14rem minmax(0, 1fr);
  gap: 1.25rem 2rem;
  margin: 0;
}
.facts dt, .legal dt {
  font-family: var(--font-display);
  font-size: .85rem;
  font-weight: 600;
  letter-spacing: -.01em;
}
.facts dd, .legal dd { margin: 0; color: var(--muted); }

/* ── close ───────────────────────────────────────────────────────────────────── */

.close { border-top: 1px solid var(--line); }
.close .actions { margin-top: 1.5rem; }

/* A page head has no figure beside it, so the lede takes the measure the rest of the
   page reads at — the same 38rem the legal pages and the institutional block use.
   Not the full column: at 1.15rem, 62rem is a hundred characters a line and the eye
   loses the return. The point is that the opening sentence and the prose under it are
   one column, which is what makes either width look deliberate. */
.page-head .lede { margin-bottom: 0; }
/* The same measure for the body of those pages. Bare paragraphs inside `.facts` are a
   subpage thing — the front page puts facts in a `dl`, whose grid already gives them a
   column — and until now they had no measure at all. */

/* ── the one moment of motion ────────────────────────────────────────────────── */

/* A build is assembled outward, so the shells arrive that way — once, on load, and
   nowhere else on the page. */
@media (prefers-reduced-motion: no-preference) {
  .bar i { animation: grow .5s cubic-bezier(.2, .7, .3, 1) backwards; }
  .bar i:nth-child(2) { animation-delay: .1s; }
  .bar i:nth-child(3) { animation-delay: .2s; }
}
@keyframes grow { from { transform: scaleX(0); } }

/* ── pages whose text is a lawyer's, not ours ────────────────────────────────── */

/* A written one. Facts as a definition list, the rest as prose at a measure somebody
   can actually read — the same furniture as the marketing pages, because a legal page
   styled like an afterthought reads like one. Each heading opens a block, so the space
   goes above it rather than below the paragraph before. */
.legal { padding-bottom: 4rem; }
.legal p { color: var(--muted); }
/* A cookie name and a CSP directive are literals: the reader is meant to be able to
   match them against what their browser shows, so they are set in the display face
   rather than described in prose. */
.legal code { font-family: var(--font-mono); font-size: .9em; color: var(--ink); }
/* Which of three texts a reader is holding. On the German terms it says "this is the
   binding one"; on the translations, "this is not". Set apart because it is a statement
   *about* the page rather than part of it — a reader who skips it should still not be
   able to miss it. */
.legal .notice {
  border-left: 3px solid var(--line-strong);
  padding: .1rem 0 .1rem 1rem;
  margin-bottom: 2.5rem;
}
.legal .eyebrow { margin-top: 3rem; }
.legal > :first-child { margin-top: 0; }

/* Content only its owner can supply — a legal text, a phone number. Marked so it can
   never be mistaken for the finished thing by a visitor OR by us. Standalone rather
   than nested under any one page's class: the contact page needs it too, and a
   placeholder that only looks like one on some pages is worse than none. */
.marker {
  font-family: var(--font-display);
  font-size: .72rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--warn-ink);
  background: var(--warn-bg);
  display: inline-block;
  padding: .3rem .6rem;
  margin-bottom: 1.25rem;
}
/* ── the institutional track ─────────────────────────────────────────────────── */

.institutes { padding: 2.75rem 0; }

.enquiry { padding: 0 0 2.75rem; max-width: 34rem; }
.enquiry form { display: grid; gap: .9rem; }
.enquiry label { display: grid; gap: .3rem; font-size: .9rem; color: var(--muted); }
.enquiry input, .enquiry textarea {
  padding: .55rem .65rem;
  border: 1px solid var(--line-strong);
  background: var(--card);
  font: inherit;
  color: var(--ink);
}
.enquiry textarea { resize: vertical; }
.enquiry button {
  justify-self: start;
  padding: .7rem 1.3rem;
  border: 0;
  background: var(--accent);
  color: var(--on-accent);
  font-family: var(--font-display);
  font-size: .9rem;
  cursor: pointer;
}
.enquiry button:hover { background: var(--ink); }

/* The honeypot. Off-screen rather than display:none — some bots skip what is not
   rendered, and this one is meant to be found and filled. aria-hidden and tabindex=-1
   keep it away from anybody using a keyboard or a screen reader. */
.trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.said { color: var(--accent); }
.enquiry .said, .enquiry .warning { margin: 1.25rem 0 0; max-width: 34rem; }

/* ── narrow ──────────────────────────────────────────────────────────────────── */

@media (max-width: 52rem) {
  .hero { grid-template-columns: 1fr; gap: 2.5rem; padding: 2.5rem 0 3.5rem; }
  .paths { grid-template-columns: 1fr; gap: 2rem; }
  .runs { display: none; }
  .poloidal { max-width: 15rem; }
  .shells > li, .plans > li { grid-template-columns: 1fr; gap: .5rem; }
  .bar { width: 100%; max-width: 18rem; }
  .facts dl, .legal dl { grid-template-columns: 1fr; gap: .35rem; }
  .facts dd, .legal dd { margin-bottom: .9rem; }
}

/* ── the checkout ────────────────────────────────────────────────────────────── */

/* The basket, as the page that turns it into an order shows it back. Two columns and
   no prices: what a line costs is the *provider's* answer (it has to be, in order to
   tax it), and a total computed here would be a second number to reconcile against the
   one somebody was actually charged. So this says what was ordered, and the provider
   says what it comes to. */
table.basket { border-collapse: collapse; width: 100%; max-width: 30rem; margin: 0 0 2rem; }
table.basket th, table.basket td {
  text-align: left;
  padding: .55rem .75rem .55rem 0;
  border-bottom: 1px solid var(--line);
}
table.basket th {
  font-family: var(--font-display);
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--muted);
}
table.basket td:last-child, table.basket th:last-child { text-align: right; width: 6rem; }

/* The checkout's basket is a *form*, not a receipt: three columns, and the last one is
   a control rather than a figure. So it undoes the right-aligned number column above —
   a select flush against the right edge with a heading over it reads as a total — and
   gives the product column room. "PROCESS solving (systems code)" wrapped to four lines
   in the six-rem column the read-only table leaves it. */
table.basket.editable { max-width: 44rem; }
table.basket.editable td, table.basket.editable th { text-align: left; width: auto; }
/* Seats — a two-digit field and its heading, nothing more. */
table.basket.editable td:nth-child(2), table.basket.editable th:nth-child(2) {
  width: 6rem;
}
/* The term. Sized by its longest option — "19,00 € / Semester" in German, which is the
   widest of the twelve — because a select that clips its own text makes the reader
   open it to find out what they are already looking at. */
table.basket.editable td:nth-child(3), table.basket.editable th:nth-child(3) {
  width: 14rem;
}
/* What the line comes to. Right-aligned and tabular so the column reads as a column of
   figures rather than as three unrelated strings. */
table.basket.editable td:last-child, table.basket.editable th:last-child {
  width: 7rem;
  text-align: right;
  font-variant-numeric: tabular-nums;
}
table.basket.editable input { width: 4.5rem; }
table.basket.editable select { width: 100%; }
