/* NIX — /marketplace
   ══════════════════════════════════════════════════════════════════════════
   The store. Built on the same tokens as everything else — paper, surface,
   rule, the two weights — so it reads as a room in the same house rather than
   a shop that rented the address. No colour of its own: the site is monochrome
   by decision, and a price is not a reason to break that. The pill's shape is
   what makes it read as a price.

   TWO PANELS, the way the app lays a room out: a narrow one for getting
   around, a wide one for what you came to look at. The rail here is always
   out — no ring, no sliding — and what is in it is the site's own four links,
   the same ones every other page carries, so the store is a room in the house
   rather than a shop with its own front door. The shelf's filters are a header
   at the top of the panel beside it: a filter is about what is on the shelf,
   the rail is about which room you are in.

   The frame is the window and each panel scrolls inside itself, until 900px,
   where the page scrolls instead and the panels grow to their contents. That
   is the reverse of the desktop arrangement and the honest one on a phone.
   ══════════════════════════════════════════════════════════════════════════ */

/* THE PANEL, AND THE SHELL AROUND IT IS shell.css's. What used to be here —
   a grid of two columns, a gutter on four sides, a rail that was always out —
   was the shell rewritten under other names, and the parts it did not rewrite
   are the parts this page went without: the ring, its travel, and any way to
   close the rail at all. The page is .nav-shell now; what is left in this file
   is the shelf.

   .mk is the panel's own scroller. The frame is the window and the panel
   scrolls inside itself, until 900px, where the page scrolls instead and the
   panel grows to its contents — the reverse of the desktop arrangement and
   the honest one on a phone. */
.mk {
  min-height: 0;
}

/* The shared panel. Three grounds, and each one earns its place: the page is
   paper, a panel sits on it in surface, and a card inside a panel sits on
   chip. Two would leave the cards invisible against their own container. */
.mk-panel {
  /* The value the store's rail takes; .mk-main overrides it with
     --nix-panel below, since both of them are content rather than rail. */
  background: var(--nix-rail);
  border-radius: var(--radius-xl);
  padding: var(--shell-pad);
  /* Each panel is its own scroller — the app's arrangement, and the reason
     the frame above can stay exactly the height of the window. min-height:0
     is what lets a grid item shrink below its content far enough to scroll;
     without it the panel grows and pushes the frame open again. */
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
}

.mk-hero__link:focus-visible,
.mk-hero__get:focus-visible,
.mk-hero__back:focus-visible,
.mk-shelf__item:focus-visible,
.mk-creator:focus-visible,
.mk-item:focus-visible,
.mk-creator-row:focus-visible {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
}

/* ── Sections ───────────────────────────────────────────────────────────── */
/* The content panel takes --nix-panel; .mk-panel's own --nix-rail stays for
   the rail, which shares that value with the cards in dark. Both carry
   .mk-panel, so the override has to name the one that is content. */
.mk-main {
  background: var(--nix-panel);
  /* The same entrance the app's store makes, at the same duration token: a
     catalogue that appears fully formed reads as a page that was already
     there, which is exactly what a drill-in must not look like. */
  animation: mk-fade var(--dur-3) var(--ease-out-expo) both;
}

@keyframes mk-fade {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: none; }
}

.mk-main { display: flex; flex-direction: column; gap: var(--space-3); }

.mk-sec { display: flex; flex-direction: column; gap: var(--shell-pad); }

.mk-sec__title {
  font-size: var(--text-sm);
  font-weight: 400;
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--nix-text-soft);
}

.mk-empty { color: var(--nix-text-soft); font-size: var(--text-base); }

.mk-empty a { color: var(--nix-text); }

/* The monogram every mark on this page falls back to. agentbase.listing and
   agentbase.author carry no image, so rather than a grey rectangle that reads
   as a picture which failed to load, the initial says plainly that the mark is
   generated. */
.mk-mono {
  font-size: inherit;
  font-weight: 300;
  letter-spacing: var(--tracking-tight);
  color: var(--nix-text-soft);
  line-height: 1;
}

/* ── The window ─────────────────────────────────────────────────────────
   One agent, the size of the room. It was a row — 132px thumbnail, three
   lines, a price at the far edge — which is the grid's own card with bigger
   type, so the front window looked like the first shelf twice.

   Its two controls FLOAT on it: the shelves at the top, and the shell's ring
   in the corner (parked there by shell.css, not by this file). Neither is
   about the agent under them, and a band of their own would push the whole
   catalogue down by the height of chrome. */
.mk-hero {
  position: relative;
  /* THE MARK'S SIZE IS THE ROOM THE MARK TAKES. It is drawn behind the copy,
     so nothing negotiated the space between them: each bracket needed a
     hand-tuned font-size AND a hand-tuned `top`, and the gap between mark and
     copy still drifted by seventy pixels depending on how much copy there
     was. One custom property drives both now — the mark's size, and the
     padding that keeps the copy clear of it — so a bracket sets one number. */
  --mark-size: 150px;
  /* THE CHROME IS NO LONGER PART OF THE BAND. The rung under this line used to
     be the shelf's own height: the bar floated inside this window, and both
     children starting at the same origin put an opaque pill over the top half
     of the mark. The bar is a sticky row above the window now, so the height
     it was holding back belongs to nothing, and the window starts at its own
     padding like every other card here. */
  padding-top: calc(var(--mark-size) + var(--space-2));
  /* THE WINDOW'S HEIGHT IS A PROPERTY, NOT A LITERAL, and it is read twice:
     here, and by the account's copy of this page at the foot of the file,
     which has to restate min-height to outrank portal.css. Two literals would
     have agreed on the desktop and disagreed at every breakpoint below it. */
  --hero-h: 600px;
  min-height: var(--hero-h);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: center;
  gap: 12px;
  padding: var(--space-4);
  background: var(--chip-tint);
  border-radius: var(--radius-xl);
  overflow: hidden;
  text-align: center;
}

/* The mark, big and quiet, BEHIND the copy: neither listing nor author
   carries an image, so the initial is the picture rather than a tile that
   admits it is a placeholder. One step further in than the card it sits on,
   which is what makes it read as ground instead of as type. */
.mk-hero__mono {
  position: absolute;
  /* The same origin the copy's padding starts from; nothing floats over it any
     more, so there is no rung to clear. */
  top: calc(var(--shell-pad) + var(--space-1));
  left: 0;
  right: 0;
  /* 112, not 160. At 160 the initial was the largest object on the page by
     four times over the agent's own name — past ~100px a letterform stops
     being a mark and becomes decoration competing with what it stands for. */
  /* ARTWORK, not type: a watermark is a picture of a letter, so it is sized
     against the card it fills rather than against the ramp. */
  font-size: var(--mark-size);
  font-weight: 300;
  letter-spacing: var(--tracking-tight);
  line-height: 1;
  color: var(--mark-ground);
  pointer-events: none;
}

/* The whole window is the link; the name is what it is called. Stretched
   under the copy rather than wrapped around it, so the button and the pills
   over it stay pressable. */
.mk-hero__link { text-decoration: none; color: inherit; }

.mk-hero__link::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
}

.mk-hero__name {
  position: relative;
  z-index: 1;
  font-size: var(--text-display);
  font-weight: 300;
  letter-spacing: var(--tracking-tight);
  /* 1.05 with no measure: a two-word agent name wrapped into itself. */
  line-height: 1.1;
  max-width: 20ch;
  text-wrap: balance;
}

.mk-hero__tick {
  margin-left: 8px;
  font-size: var(--text-md);
  color: var(--nix-text-soft);
}

.mk-hero__sum {
  position: relative;
  z-index: 1;
  max-width: 60ch;
  color: var(--nix-text-soft);
  font-size: var(--text-base);
}

/* ONE BUTTON, AND THE PRICE IS ITS LABEL. "Get" when the agent is free, the
   amount when it is not — the thing you press and the thing you pay are never
   two objects to reconcile, and a separate price chip put the number where
   nothing could be pressed. */
.mk-hero__get {
  position: relative;
  z-index: 2;
  margin-top: 4px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 96px;
  padding: 12px 24px;
  border-radius: var(--radius-pill);
  background: var(--nix-ink);
  color: var(--nix-on-ink);
  text-decoration: none;
  font-size: var(--text-base);
}

.mk-hero__get:hover { background: color-mix(in srgb, var(--nix-ink) 88%, var(--nix-paper)); }


.mk-hero__links {
  position: relative;
  z-index: 2;
  display: flex;
  gap: var(--shell-gap);
  flex-wrap: wrap;
  justify-content: center;
}

.mk-hero__link-chip {
  padding: 6px 14px;
  border-radius: var(--radius-pill);
  background: var(--chip-hover);
  color: var(--nix-text);
  text-decoration: none;
  font-size: var(--text-base);
}

/* Back, in the corner the shelf page's ring occupies — the same gesture with
   the same target size, so the two pages do not move the way out.

   It carries the rung itself: --chrome-h used to be declared on .mk-hero for
   the shelf that floated there, and the shelf is a row above the window now.
   An inherited property that stops being declared does not fall back to the
   old value, it falls out — this button would have been sized by its glyph. */
.mk-hero__back {
  position: absolute;
  top: var(--shell-pad);
  left: var(--shell-pad);
  z-index: 3;
  --chrome-h: 34px;
  width: var(--chrome-h);
  height: var(--chrome-h);
  border-radius: var(--radius-pill);
  background: var(--chip-float);
  box-shadow: var(--lift-2);
  color: var(--nix-text);
  display: grid;
  place-items: center;
}

.mk-hero__back svg { width: 16px; height: 16px; }

.mk-hero--one { --hero-h: 420px; }

/* ── THE ACCOUNT'S PANEL IS THE STORE'S PANEL ────────────────────────────
   /my/store draws THIS body, and the difference the reader saw was never in
   the body — it was in the box around it. Out here <main> is
   `mk mk-panel mk-main`: shell-pad on all four sides and a flex column with
   space-3 between its sections. In /my it is the portal layout's own
   `page page--flow`, which is display:block with no gap and a wider inset on
   the sides only — so the shelves ran narrower (the hero, unchanged, read as
   bigger in a narrower column) and the space between Creators and Agents was
   whatever the sections' own margins happened to be rather than the one gap
   the store is laid out on.

   The two values ARE the public panel's two values, named the same way, so
   the stores cannot drift apart on this: change .mk-panel's padding or
   .mk-main's gap and both legs move together.

   Scoped to .nix-account, and the sheet itself is the second half of the
   scope: pages/store.css is linked only where page_css is 'store', which is
   /my/store and its two children — the portal's other dozen pages never see
   this rule because they never load the file. */
.nix-account main.page--flow {
  padding: var(--shell-pad);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  /* AND THE LINES ARE THE SAME HEIGHT. Odoo's frontend bundle sets
     `body { line-height: var(--body-line-height) }`, which computes to 24px;
     the standalone pages carry no such rule and every box on them measures at
     `normal`. Nothing in the markup differed — a card was 110px here against
     95px out there, a creator 216 against 212, and the Agents shelf 65px
     taller — because each line inside them was four pixels taller. Measured on
     both legs at the same panel width. */
  line-height: normal;
}

/* AND NOTHING IN IT CARRIES A MARGIN IT DID NOT ASK FOR. base.css opens with
   `* { margin: 0 }` and every box in this file is laid out on gaps because of
   it; on the standalone pages that is the last word, and in /my Odoo's bundle
   is linked after ours and puts h2's bottom margin back. Eight pixels under
   both shelf titles, which is the whole of what was left between the two
   stores once the lines matched.

   The same declaration as base.css's, restated for this subtree rather than
   fought rule by rule: an element-by-element list would be a list to keep in
   step with a stylesheet we do not own. */
.nix-account main.page--flow * {
  margin: 0;
}

/* AND NOTHING IN IT UNDERLINES ITSELF ON HOVER. Odoo's bundle carries
   `a:hover { text-decoration: underline }`, which is (0,1,1) — one class more
   specific than the `text-decoration: none` each of this file's links declares
   for itself, and linked after us. So every card, creator and the price button
   grew a rule under it on the way past, on the account's leg only: out on
   /marketplace that bundle is not on the page at all.

   Named on the panel rather than per class: the store's links are the store's
   links wherever they are drawn, and a list of them here would be a list to
   keep in step with the markup. */
.nix-account main.page--flow a:hover {
  text-decoration: none;
}

/* AND THE WINDOW IS NOT THE PANEL. portal.css grows the first thing in the
   account's panel to fill it —

     #wrapwrap.nix-account > main.page > :first-child { flex: 1 0 auto;
                                                        min-height: 100% }

   which is what stops a single settings card from floating with the foot
   pulled up under it. On the store the first thing is the shop window, so the
   window took the height of the panel: one agent, measured at 924px against
   the 600 this file asks for, with the catalogue below the fold. That is the
   "hero bigger than the marketplace's" the reader saw, and it was never this
   file's number.

   One class further in than that rule, because equal specificity would lose
   on order: portal.css is linked after the page sheet. The height comes back
   as --hero-h rather than as 600px, so the override tracks every breakpoint
   above instead of pinning the desktop value on a phone.

   AND IT ANSWERS THE POSITION, NOT THE ELEMENT. It named .mk-hero while the
   window was the first thing in the panel; the sticky bar is now, and it grew
   into a pill the height of the whole panel the moment it moved. Whatever
   stands first here is content and not a card that has to fill the room. */
#wrapwrap.nix-account > main.page.page--flow > :first-child {
  flex: 0 0 auto;
  min-height: 0;
}

/* AND THE WINDOW KEEPS ITS OWN HEIGHT AFTER THAT RESET. Same specificity as
   the line above and written after it on purpose: whichever of the two is
   first in the panel, the hero is 600px because this file says so and nothing
   else stretches. */
#wrapwrap.nix-account > main.page.page--flow > .mk-hero {
  min-height: var(--hero-h);
}

/* THE SHELVES ARE THIS PAGE'S HEADER, and they behave like the other two the
   site has: .nix-sectionbar on /agent-base and .nix-blogbar on the blog are
   rows in the page's flow that stick to the top of the scroller, so this one
   is sticky at the same 8px with the same blur behind it. It used to be
   absolutely positioned inside the hero, which meant it scrolled away with the
   first agent — a filter you can only reach at the top of a list is a filter
   for a list you have not read yet.

   Centred by auto margins on a max-content box rather than by left/transform:
   in the flow that is what centring is, and it is also what let the phone rule
   below go back to being the same margin the other two bars take.

   They scroll sideways rather than wrapping: five pills and a narrow panel
   would otherwise become two rows. */
.mk-shelf {
  position: sticky;
  top: 8px;
  z-index: 30;
  display: flex;
  align-items: center;
  gap: 6px;
  width: max-content;
  max-width: 100%;
  margin-inline: auto;
  /* The pill is a surface floating over the page's own ground, exactly as
     .nix-sectionbar is, and what shows through the gap around it is the
     panel scrolling underneath. */
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  /* The bar owns its own height now that it is not measured against the window
     it used to float on. */
  --chrome-h: 34px;
  min-height: var(--chrome-h);
  box-sizing: border-box;
  padding: 6px;
  border-radius: var(--radius-pill);
  /* A control that leaves the plane moves AWAY from the ground it leaves.
     --nix-panel is darker than the window in dark — a hole punched through to
     the page — and barely a step from it in light. */
  background: var(--chip-float);
  box-shadow: var(--lift-2);
  overflow-x: auto;
  scrollbar-width: none;
  /* The fade lands on PADDING rather than on a pill: at 6px of inline padding
     a 16px mask ate ten pixels of the first and last labels. */
  padding-inline: 16px;
}

.mk-shelf::-webkit-scrollbar { display: none; }

/* ── THE BAR CLEARS THE RING ON A PHONE ──────────────────────────────────
   The same 56 and 24 .nix-sectionbar and .nix-blogbar take in components.css,
   and for the same reason: below 720px the rail covers the page rather than
   standing beside it, so the ring in the panel's top-left corner is the only
   way into the menu — and it was sharing those pixels with this bar's first
   word. Here rather than beside them because this sheet is linked after that
   one and the centred margin above is written at the same specificity: over
   there the rule would be overwritten at exactly the width it matters.

   The measure pays for the margins. `max-width: 100%` resolves against the
   containing block and margins are laid outside it, so without the subtraction
   the pill comes out its full width and then takes 80px on top of it. */
@media (max-width: 720px) {
  .mk-shelf {
    margin-inline: 56px 24px;
    max-width: calc(100% - 56px - 24px);
  }
}

/* ── AND INSIDE THE ACCOUNT, WHERE THE PANEL FLATTENS ITS CHILDREN ───────
   Two rules reach every direct child of the portal's panel and both of them
   land on this bar: shell.css's `main.page > *` sets width:auto and
   max-width:none so an Odoo form fills the panel, and portal.css's zeroes the
   margins. Between them the pill stretched to the panel's full width and
   stopped being centred — and on a phone it stopped clearing the ring with it.

   One id and one class further in than either, and it restates the three
   declarations they take away rather than fighting them one at a time. */
#wrapwrap.nix-account > main.page > .mk-shelf {
  width: max-content;
  max-width: 100%;
  margin-inline: auto;
}

@media (max-width: 720px) {
  #wrapwrap.nix-account > main.page > .mk-shelf {
    margin-inline: 56px 24px;
    max-width: calc(100% - 56px - 24px);
  }
}

/* AND ONLY WHEN IT SCROLLS. The mask was unconditional, so in the common case
   — five pills that fit — the current pill and the last one were permanently
   half-faded into the window for no reason. The script adds the class when
   scrollWidth exceeds clientWidth. */
.mk-shelf.is-scrollable {
  -webkit-mask-image: linear-gradient(to right, transparent 0, #000 16px, #000 calc(100% - 16px), transparent 100%);
  mask-image: linear-gradient(to right, transparent 0, #000 16px, #000 calc(100% - 16px), transparent 100%);
}

.mk-shelf__item {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  border-radius: var(--radius-pill);
  color: var(--nix-text-soft);
  text-decoration: none;
  font-size: var(--text-base);
  white-space: nowrap;
}

.mk-shelf__item svg { width: 16px; height: 16px; flex: none; }

.mk-shelf__item:hover { color: var(--nix-text); }

/* "All" is current when no shelf is chosen, so it carries the fill by default
   and gives it up — is-off — the moment one is. */
.mk-shelf__item.is-on,
.mk-shelf__item:not(.is-off):first-child {
  background: var(--chip-hover);
  color: var(--nix-text);
}

.mk-shelf__item.is-off { background: transparent; color: var(--nix-text-soft); }

/* ── Creators ───────────────────────────────────────────────────────────
   Not "Companies". The same row carries a studio with nine agents and one
   person who published one on a Sunday, and the old word told half of them
   they were in the wrong shop.
   The picture IS the tile. The card around it was a second box holding one
   box: two radii, two grounds and twelve pixels of padding to say what the
   mark already said. Portrait, because a square reads as one more app icon —
   the shape the agents' own marks carry a section below — and a shop is not
   a product. */
/* ONE ROW THAT SLIDES, and it stops where the creators do. It was a grid that
   wrapped: eight shops came out as seven and a lone eighth on a second line,
   under a heading that had already been read — a shelf with a stray tile
   rather than a shelf. A catalogue of shops has no natural number, so the row
   scrolls sideways instead of reflowing, exactly as the store's own shelf pills
   above it do.

   The tiles keep their width. Letting them stretch is what once turned a
   catalogue of one creator into a 123px portrait beside 1200px of empty
   grid. */
.mk-creators {
  display: flex;
  gap: var(--shell-pad);
  overflow-x: auto;
  /* Proximity, not mandatory: a reader dragging through eight shops should be
     able to stop between two of them, and mandatory snapping fights a trackpad
     flick that was only ever meant to move the row a little. */
  scroll-snap-type: x proximity;
  scrollbar-width: none;
  /* The focus ring is drawn OUTSIDE the tile and this box clips: without the
     block padding a keyboard user's ring is sliced along the top and bottom. */
  padding-block: 3px;
}

.mk-creators::-webkit-scrollbar { display: none; }

/* AND IT FADES ONLY WHEN THERE IS SOMETHING PAST THE EDGE — the same condition
   and the same class the shelf uses, measured by the same script. An
   unconditional mask half-erases the last shop on every catalogue that fits. */
.mk-creators.is-scrollable {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 48px), transparent 100%);
  mask-image: linear-gradient(to right, #000 calc(100% - 48px), transparent 100%);
}

.mk-creator {
  flex: none;
  width: 140px;
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
  gap: var(--shell-gap);
  text-decoration: none;
  color: inherit;
}

.mk-creator__art {
  aspect-ratio: 3 / 4;
  border-radius: var(--radius-chip);
  /* --chip-tint, not --chip-sunk. Every other rung mixes toward the ink;
     --chip-sunk mixes toward the PAPER, which is right for a well inside a
     card and wrong for the one tile this system gives no card: on the panel
     it landed a hair above the page and the portrait became a ghost. */
  background: var(--chip-tint);
  display: grid;
  place-items: center;
  font-size: var(--text-2xl);
  transition: background var(--dur-2) ease;
}

.mk-creator:hover .mk-creator__art { background: var(--chip-hover); }

.mk-creator__name { font-size: var(--text-base); text-align: center; }

/* ── The grid of agents ─────────────────────────────────────────────────── */
.mk-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
  gap: var(--shell-gap);
}

.mk-item {
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--shell-pad);
  padding: var(--shell-pad);
  background: var(--chip-tint);
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: inherit;
  transition: background var(--dur-2) ease;
}

.mk-item:hover { background: var(--chip-hover); }

.mk-item__art {
  aspect-ratio: 1;
  /* One rung below the card holding it. */
  border-radius: var(--radius-xs);
  background: var(--chip-sunk);
  display: grid;
  place-items: center;
  font-size: var(--text-lg);
}

.mk-item__body { display: flex; flex-direction: column; gap: 4px; min-width: 0; }

/* One line, then an ellipsis: names are author-supplied and the grid stretches
   every card in a row to the tallest one. */
.mk-item__name {
  font-size: var(--text-base);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Two lines, then an ellipsis. A summary is one line by contract, but a
   contract is not a constraint the database enforces, and one long entry must
   not set the height of every row beside it. */
.mk-item__sum {
  color: var(--nix-text-soft);
  font-size: var(--text-sm);
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.mk-item__by { color: var(--nix-text-soft); font-size: var(--text-xs); }

/* ── The button every row ends in ───────────────────────────────────────
   The same rule the window follows, one rung quieter: tinted rather than
   solid, because a dozen solid buttons and the one in the window would rank
   the same and only one of them is the page's action. */
.mk-get {
  flex: none;
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 72px;
  padding: 7px 14px;
  border-radius: var(--radius-pill);
  /* ITS OWN RUNG. It was --chip-hover, the same value the row takes on hover,
     so the control vanished at the moment the pointer reached it. It moves
     WITH the row now: the card is the link, and this is the part that says
     what pressing it costs. */
  background: var(--chip-control);
  color: var(--nix-text);
  font-size: var(--text-sm);
  white-space: nowrap;
  transition: background var(--dur-2) ease, color var(--dur-2) ease;
}

.mk-item:hover .mk-get,
.mk-item:focus-visible .mk-get { background: var(--nix-ink); color: var(--nix-on-ink); }

/* ── One agent, one shop: the two columns and what is in them ──────────── */
.mk-cols {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: var(--space-3);
  align-items: start;
}

.mk-cols__main,
.mk-cols__side { display: flex; flex-direction: column; gap: var(--space-3); min-width: 0; }

/* Written before .mk-cols on purpose would lose: a later rule of equal
   specificity wins, so the modifier stands AFTER the base. */
.mk-cols--solo { grid-template-columns: minmax(0, 1fr); }

/* With nothing in the main column the blocks are the page: a capped row, not
   a 320px gutter with six hundred pixels of nothing beside it. */
.mk-cols--solo .mk-cols__side {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 420px));
  justify-content: start;
  align-items: start;
  gap: var(--space-2);
}

/* What the page says when the author wrote no description. It is the same
   voice as the description it replaces, not an error and not a placeholder
   box: the page is honest about the gap and moves on. */
.mk-one__nodesc {
  color: var(--nix-text-quiet);
  font-size: var(--text-base);
  max-width: 72ch;
}



.mk-block { display: flex; flex-direction: column; gap: var(--shell-pad); }

.mk-creator-row {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr);
  align-items: center;
  gap: var(--shell-pad);
  padding: var(--shell-pad);
  background: var(--chip-tint);
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: inherit;
}

.mk-creator-row:hover { background: var(--chip-hover); }

.mk-creator-row__art {
  aspect-ratio: 1;
  /* One rung below the card holding it. */
  border-radius: var(--radius-xs);
  background: var(--chip-sunk);
  display: grid;
  place-items: center;
  font-size: var(--text-lg);
}

.mk-creator-row__who { display: flex; flex-direction: column; gap: 4px; min-width: 0; }

.mk-creator-row__name { font-size: var(--text-base); }

.mk-creator-row__tag { color: var(--nix-text-soft); font-size: var(--text-sm); }

/* Labels and values, read rather than pressed, so none of them is a chip that
   looks like it filters something. */
.mk-facts {
  /* A list of pairs, not a banner: at full panel width the label and its value
     sat six hundred pixels apart. */
  max-width: 420px;
  padding: var(--space-1) var(--shell-pad);
  background: var(--chip-tint);
  border-radius: var(--radius-sm);
}

.mk-fact {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--shell-pad);
  padding: var(--shell-gap) 0;
}

.mk-fact__k { color: var(--nix-text-soft); font-size: var(--text-sm); }

.mk-fact__v { font-size: var(--text-base); text-align: right; }

.mk-vers { display: flex; flex-direction: column; gap: var(--shell-gap); }

.mk-ver {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: var(--shell-pad);
  background: var(--chip-tint);
  border-radius: var(--radius-sm);
}

.mk-ver__head { display: flex; justify-content: space-between; gap: var(--shell-gap); }

.mk-ver__name { font-size: var(--text-base); }

.mk-ver__when { color: var(--nix-text-soft); font-size: var(--text-sm); }

.mk-ver__notes { color: var(--nix-text-soft); font-size: var(--text-sm); line-height: 1.5; }

@media (max-width: 900px) {
  .mk-cols { grid-template-columns: minmax(0, 1fr); }
  /* 280 with a 120px mark left 88px for a 115px copy stack, so from 641 to 900
     the name sat INSIDE the letter. */
  .mk-hero { --hero-h: 380px; --mark-size: 88px; }
  .mk-hero__name { font-size: var(--text-xl); }
}

/* ── /marketplace/<slug> and /marketplace/by/<slug> ─────────────────────── */
.mk-one__desc {
  color: var(--nix-text-soft);
  font-size: var(--text-base);
  line-height: 1.6;
  /* A paragraph at 1100px is 140 characters to the line; the eye loses the
     start of the next one somewhere past 80. */
  max-width: 72ch;
  /* Space rather than a rule, like everything else on this page. */
  padding-top: var(--space-2);
}


/* ── Overrides that have to stand last ────────────────────────────────────
   A media query adds no specificity, so a block written above a rule of the
   same selector loses to it at every width. These were higher up and every
   declaration in them was dead — including the reduced-motion opt-out, which
   is not a nicety: it is what a reader who asked their operating system for
   no motion gets. Position is the only thing that makes them apply. */

@media (max-width: 900px) {
  /* THE PANEL KEEPS ITS SCROLLER, and this is a bug fix rather than a
     preference. `.mk-panel { overflow: visible }` used to stand here so the
     PAGE would scroll instead — which worked while the frame and the panel
     were two elements. They are one now (`class="mk mk-panel mk-main"`), so
     the shorthand landed on the same box as `.mk`'s own `overflow-y: auto`,
     reset it by source order, and left the phone with a clipped page: 806px
     of catalogue inside a 707px box, with <html> and <body> locked to the
     viewport by the shell. Nothing scrolled at all.

     The rail is shell.css's problem at this width: it covers instead of
     pushing, which is what a phone menu is. */
  /* A row card is content, and content is narrower than the panel holding it:
     single-column, this put a name and its button 559px apart — the defect
     the fact list was capped for. */
  .mk-grid { grid-template-columns: 1fr; }
  .mk-item { max-width: 560px; }
}

/* ── The phone ────────────────────────────────────────────────────────────
   AT THE FOOT OF THE FILE, and that is the whole point: a media query adds no
   specificity, so a block standing above a rule of the same selector loses to
   it at every width — which is how this file once shipped four declarations
   describing a single-column layout the store never had.

   The window keeps its shape and gives up height. The shelves are not here:
   components.css already moves that pill off the ring at 720, with the same
   two numbers the site's other three bars deduct. */
@media (max-width: 640px) {
  /* NO PANEL ON A PHONE. A card inside a window needs a window, and a phone
     has none: the panel was a second rounded box tracing the edge of the
     screen, paying a radius and 12px of gutter to say nothing. The content
     sits on the page; the window and the rows keep their own corners. */
  .mk-main {
    background: transparent;
    border-radius: 0;
    padding: var(--shell-gap) var(--shell-gap) var(--space-3);
  }
  /* THREE QUARTERS OF THE SCREEN. On a phone the window is the page's first
     impression and 300px was a third of it — a card, not a window. svh after
     vh on purpose: on iOS `vh` is measured against the viewport with the
     address bar HIDDEN, so 75vh is taller than three quarters of what you can
     actually see until you scroll; svh is the small viewport, which is the one
     the reader is looking at. Browsers that never heard of svh keep the vh
     line above it. */
  .mk-hero,
  .mk-hero--one {
    --hero-h: 75vh;
    --hero-h: 75svh;
    padding: var(--space-2);
  }
}

@media (max-width: 480px) {
  .mk-hero { --mark-size: 96px; }
  .mk-hero__name { font-size: var(--text-xl); }
  .mk-creator { width: 112px; }
}
