@charset "UTF-8";
/* Store Dashboard — /dashboard.
 *
 * Its own stylesheet, loaded nowhere else. The dashboard is not a
 * storefront page: it carries none of showroom.css, has no template and
 * no store tokens, and a store's own colours must not be able to make
 * its control panel unreadable. Flat CSS with no Sass features, like
 * embed.scss, so the built file and this one stay legible side by side.
 */
:root {
  --d-bg: #f4f5f7;
  --d-panel: #ffffff;
  --d-ink: #16181d;
  --d-muted: #666c78;
  --d-line: #e2e5ea;
  --d-accent: #177a3d;
  --d-accent-ink: #ffffff;
  --d-danger: #b3261e;
  --d-radius: 8px;
  /* Amber: a note the operator should read, and the band with unpublished
     changes. One palette for both. */
  --d-warn-ink: #8a4b00;
  --d-warn-bg: #fff4e5;
  --d-warn-line: #f0c98a;
  /* One type scale, one spacing scale, two control heights. Every size in
     the dashboard's own interface is one of these, so the same thing is
     the same size on every page and inside the split pages' control rail
     as outside it:

       12  meta: badges, chips, counts, the sidebar's kicker
       13  notes, help under a field, field labels, table headers
       15  body, controls, table cells, a row's name, a sub-heading
       17  a panel's heading, everywhere, the control rail included
       24  the page's heading, the sign-in card's included

     Spacing is 4 / 8 / 12 / 16 / 24 / 32: a panel is padded 16 and panels
     are 16 apart, inside the split and out. A button, an input and a
     select are 40px tall; a small one (the preview's bar, the draft band,
     a row's actions, pagination) is 32; a reorder arrow is 32 x 28 in
     every list. Nothing is written in capitals by the stylesheet: a
     label says what it says, in sentence case.

     The example miniatures (.dash-x-*) are drawings of a shop, sized to
     the card, and the preview iframes are the shop itself; neither is on
     this scale. */
  --d-text-meta: 12px;
  --d-text-note: 13px;
  --d-text-body: 15px;
  --d-text-heading: 17px;
  --d-text-page: 24px;
  --d-pad: 16px;
  --d-gap: 16px;
  --d-control-h: 40px;
  --d-control-h-small: 32px;
}

.dash {
  margin: 0;
  background: var(--d-bg);
  color: var(--d-ink);
  font-family: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  font-size: var(--d-text-body);
  line-height: 1.5;
}

.dash * {
  box-sizing: border-box;
}

/* A link inside a sentence (a note naming another page, Sign in's
   "Forgot your password?") in the dashboard's link colour rather than the
   browser's blue. Only a link with no class: every styled link — a
   button, a sidebar item, a chip — keeps its own colour, and :where()
   keeps this rule from outweighing any of them. */
:where(.dash) a:not([class]) {
  color: var(--d-accent);
  text-underline-offset: 2px;
}

/* ---------- the signed-out pages ---------- */
.dash-centre {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  padding: 24px;
}

.dash-card {
  width: 100%;
  max-width: 420px;
  padding: 32px;
  background: var(--d-panel);
  border: 1px solid var(--d-line);
  border-radius: var(--d-radius);
}

/* The page heading's size: signing in is a page like any other. */
.dash-card h1 {
  margin: 0 0 4px;
  font-size: var(--d-text-page);
  line-height: 1.25;
}

.dash-card .dash-sub {
  margin: 0 0 24px;
  color: var(--d-muted);
  font-size: var(--d-text-body);
}

@media (max-width: 560px) {
  .dash-centre {
    padding: 16px;
  }
  .dash-card {
    padding: 24px 16px;
  }
}
/* ---------- the shell ----------
 *
 * A sidebar and the page: `.dash-side | .dash-main`, one grid, the page's
 * column `minmax(0, 1fr)` so nothing wide inside it — a 1280px preview
 * iframe, a table — can push the grid past the window.
 *
 * The sidebar is one element at three widths, and the width is the only
 * thing that decides which: names and icons (216px) from 1100px up, an
 * icon rail (60px) below that, and on a phone (700px and down) no column
 * at all — a strip across the top with a Menu button, and the sidebar as
 * a drawer over the page. What the sidebar DRAWS at a width is a
 * container query on the sidebar itself rather than a second set of
 * media queries, because the rail has two causes — a narrow window, and
 * an owner who collapsed it by hand on a wide one — and a media query
 * can only see the first. The drawer is 300px wide, so it draws names.
 *
 * The cost is width, and it is paid by the four split pages: the preview
 * is what is left after the sidebar, the control rail and the gutters.
 * Measured on KUUL with the control rail at its 380px default — preview
 * column, then the frame fit() scales into and the Desktop render's
 * scale:
 *
 *   1440  763px  727  0.57   Desktop is where it starts (>= 0.5)
 *   1280  603    567  0.44   starts on Phone from here down
 *   1100  480    444  0.35   control rail clamped to 323
 *   1099  578    542  0.42   the sidebar is a 60px rail from here
 *    900  480    444  0.35   control rail clamped to 279
 *
 * (Re-measured 2026-09-27 after the type and spacing pass: the page's
 * gutter went 28 -> 24 and the panel's padding 20 -> 16, which gave the
 * preview and the clamped rail 8px each.)
 *
 * Collapsing the sidebar by hand at 1440 gives 919 / 883 / 0.69. Before
 * the sidebar the same column was 971 at 1440 and 811 at 1280; Compare's
 * two panes went from about 698px each at 1440 to 590, and are 586 with
 * the 16px gap and gutter Compare has now.
 */
/* The sidebar's column is painted by the page, not only by the sidebar.
   The sidebar is sticky and as tall as the window, so on its own it ends
   where the window does: a full-length screenshot, and the elastic
   overscroll past either end of a page, showed the page's grey under it.
   The body's background is the canvas's, which runs the whole length of
   the document and on past both ends, so the column is drawn there — the
   panel's white, then the sidebar's 1px line — and the sidebar's own
   background lies exactly over it. The width is one custom property on
   the body (the layout's `dash-has-side`; the signed-out pages have no
   sidebar and no column), so the grid and the paint cannot disagree
   about it. A phone has no column: plain grey. */
.dash-has-side {
  --dash-side-w: 216px;
  background: linear-gradient(to right, var(--d-panel) 0 calc(var(--dash-side-w) - 1px), var(--d-line) 0 var(--dash-side-w), var(--d-bg) 0) var(--d-bg);
}

@media (max-width: 1099px) {
  .dash-has-side {
    --dash-side-w: 60px;
  }
}
@media (min-width: 1100px) {
  .dash-side-min .dash-has-side {
    --dash-side-w: 60px;
  }
}
@media (max-width: 700px) {
  .dash-has-side {
    background: var(--d-bg);
  }
}
.dash-shell {
  display: grid;
  grid-template-columns: var(--dash-side-w) minmax(0, 1fr);
  /* The window less the store environment's top bar above it, where there
     is one (--dash-top-h, 0 without it and on a phone). */
  min-height: calc(100vh - var(--dash-top-h, 0px));
}

/* The phone's strip; nothing above 700px. */
.dash-strip {
  display: none;
}

/* Sticky and as tall as the window, so every item is in reach from the
   bottom of a long page. `position: sticky` also makes it the positioned
   ancestor an absolutely positioned child resolves against — which is
   what keeps a visually hidden name inside it rather than at the page's
   right edge (see .dash-side-label). */
.dash-side {
  container: dash-side/inline-size;
  position: sticky;
  top: var(--dash-top-h, 0px);
  z-index: 20;
  height: calc(100vh - var(--dash-top-h, 0px));
  background: var(--d-panel);
  border-right: 1px solid var(--d-line);
}

/* The scrollbar, when there is one, is the sidebar's own: a short window
   with the names showing scrolls the list and not the page. */
.dash-side-in {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 16px 8px 12px;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.dash-side-top {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
}

/* Who is signed in: a mark, and the name under a small kicker. The mark
   is what stands for the name on the rail. */
.dash-brand {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  padding: 0 4px 12px;
}

.dash-brand-mark {
  display: grid;
  place-items: center;
  flex: 0 0 32px;
  height: 32px;
  border-radius: 8px;
  background: var(--d-accent);
  color: var(--d-accent-ink);
  font-size: var(--d-text-body);
  font-weight: 700;
  line-height: 1;
}

.dash-brand-words {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* Sentence case, as written: forced capitals and the tracking that went
   with them made "Shop dashboard" shout. */
.dash-brand-kicker {
  color: var(--d-muted);
  font-size: var(--d-text-meta);
  line-height: 1.3;
}

/* A site's name is its host, which can be long and has no spaces. The
   layout marks where it may wrap — after a dot — with <wbr>, and this
   breaks inside a piece only when a piece cannot fit on a line at all:
   `anywhere` broke "webshop.mijntafel.test:8000" as "…test:8" / "000". */
.dash-brand strong {
  font-size: var(--d-text-body);
  line-height: 1.25;
  overflow-wrap: break-word;
}

/* One row per item: an icon and a name. A link or a button, drawn the
   same, because Sign out is a form and the rest are links.

   `position: relative` is load-bearing: on the rail the name becomes a
   tooltip positioned against the link. */
.dash .dash-side-link {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 36px;
  padding: 8px 12px;
  border: 0;
  border-radius: 6px;
  background: none;
  color: var(--d-ink);
  font: inherit;
  font-size: var(--d-text-body);
  line-height: 1.3;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

.dash-side-link .dash-icon {
  flex: 0 0 20px;
  color: var(--d-muted);
}

.dash .dash-side-link:hover {
  background: var(--d-bg);
}

.dash .dash-side-link:focus-visible {
  outline: 2px solid var(--d-accent);
  outline-offset: -2px;
}

/* The page you are on, or the one it belongs under. */
.dash .dash-side-link.on {
  background: #e7f3eb;
  color: var(--d-accent);
  font-weight: 600;
}

.dash-side-link.on .dash-icon {
  color: var(--d-accent);
}

/* The way to the shop (or the site): it leaves the dashboard, which
   nothing else here does, so it is coloured like a link — one external
   icon, and no ↗ after the words as well. */
.dash-side-live {
  margin: 0 0 4px;
}

.dash .dash-side-live .dash-side-link {
  color: var(--d-accent);
  font-weight: 600;
}

.dash-side-live .dash-side-link .dash-icon {
  color: var(--d-accent);
}

.dash-side-live-note {
  margin: 0 12px 8px;
}

/* The off line: the `off` icon and the sentence, in the note's muted
   colour — a fact, not a way anywhere. It is a tab stop, so the rail can
   show its tooltip on keyboard focus (partials/live_at), and it shows that
   focus the way the items do. */
.dash-side-live-off {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin: 0 0 8px;
  padding: 8px 12px;
  border-radius: 6px;
  line-height: 1.4;
}

.dash-side-live-off .dash-icon {
  flex: 0 0 20px;
  color: var(--d-muted);
}

.dash-side-live-off:focus-visible {
  outline: 2px solid var(--d-accent);
  outline-offset: -2px;
}

/* A shop's line is a sentence, not a button: "Your shop is live at
   <address>". It wraps (the address only after a dot or before a slash,
   where the partial put <wbr>), its words are ink, and the address in it
   is what looks like the link — the whole line is the link, so it is a
   big target and its name is the whole sentence. The icon stays with the
   first line. */
.dash .dash-side-live .dash-side-live-link {
  align-items: flex-start;
  color: var(--d-ink);
  font-weight: 400;
  overflow-wrap: break-word;
}

/* An inline-block, so the address goes to the next line whole rather
   than splitting at its first dot to fill this one; one too long for a
   line of its own still wraps inside, at the <wbr>s. */
.dash-side-live-where {
  display: inline-block;
  max-width: 100%;
  color: var(--d-accent);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* The sites that draw the shop in a design of their own: one quiet line
   each, under the link and in line with its words. */
/* In line with the link's words: its 12px inset, the 20px icon and the
   12px gap. */
.dash-side-live-sites {
  margin: 0 12px 8px 44px;
  color: var(--d-muted);
  font-size: var(--d-text-note);
  line-height: 1.4;
}

.dash-side-live-sites p {
  margin: 0 0 4px;
}

.dash-side-live-sites p:last-child {
  margin-bottom: 0;
}

/* "Design" and "Manage": a label over a list, at a label's size and in
   the words' own case. */
.dash-side-heading {
  margin: 16px 12px 4px;
  color: var(--d-muted);
  font-size: var(--d-text-note);
  font-weight: 600;
  line-height: 1.3;
}

.dash-side-list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* The way out, and the collapse control, at the foot however long the
   list above them is. */
.dash-side-foot {
  display: flex;
  flex-direction: column;
  gap: 2px;
  margin-top: auto;
  padding-top: 12px;
  border-top: 1px solid var(--d-line);
}

.dash-side-nav {
  margin-bottom: 16px;
}

.dash-side-form {
  margin: 0;
}

.dash-side-foot .dash-side-link {
  color: var(--d-muted);
}

/* An author `display` beats the UA's `[hidden] { display: none }`; the
   collapse control is hidden until the script is there to work it. */
.dash .dash-side-collapse[hidden] {
  display: none;
}

/* One of its two icons at a time: the chevron points the way it will
   move the sidebar. */
.dash-side-collapse .dash-icon + .dash-icon {
  display: none;
}

.dash-side-min .dash-side-collapse .dash-icon {
  display: none;
}

.dash-side-min .dash-side-collapse .dash-icon + .dash-icon {
  display: block;
}

/* Collapsing is a wide screen's choice; below 1100px the rail is not
   optional, so there is nothing to collapse. */
@media (max-width: 1099px) {
  .dash .dash-side-collapse {
    display: none;
  }
}
/* The drawer's close control: a phone's only. */
.dash-side-close {
  display: none;
}

/* ---------- the rail: icons only ----------
 *
 * Every name is still in the link — the link's accessible name, and a
 * tooltip on hover AND on keyboard focus, which a `title` would not be.
 * Faded with opacity, never `visibility` or `display`, both of which take
 * it out of the accessibility tree and leave an icon with no name.
 *
 * Positioned against the link (`position: relative` above), never loose:
 * `.dash-sr-only`'s `position: absolute` with no positioned ancestor is
 * the trap that once laid hidden spans out past the right edge and
 * scrolled this whole page 693px sideways.
 *
 * The rail does not scroll, because a scroll box clips whatever sticks
 * out of it and the tooltips stick out by design. Its items are sized to
 * fit a short laptop window (below 760px of height they tighten), and
 * only a window too short even for that gets a scrollbar back — and
 * with it tooltips cut at the rail's edge, which is the lesser loss.
 */
@container dash-side (max-width: 100px) {
  .dash-side-in {
    padding: 12px 8px;
    overflow: visible;
  }
  .dash-brand {
    justify-content: center;
    padding: 0 0 12px;
  }
  /* Visually hidden, still read out: the mark stands in for it. */
  .dash-brand-words {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .dash .dash-side-link {
    justify-content: center;
    width: 44px;
    min-height: 40px;
    margin: 0 auto;
    padding: 0;
  }
  .dash-side-label {
    position: absolute;
    top: 50%;
    left: calc(100% + 12px);
    z-index: 30;
    padding: 4px 8px;
    border-radius: 6px;
    background: var(--d-ink);
    color: #ffffff;
    font-size: var(--d-text-note);
    font-weight: 500;
    white-space: nowrap;
    opacity: 0;
    pointer-events: none;
    transform: translateY(-50%);
    transition: opacity 0.12s;
  }
  /* :focus-visible and not :focus: a click on "Your shop is live" opens
     a tab and leaves focus on the link, and :focus would leave its
     tooltip standing there. Script focus matches :focus-visible in a focused
     window too (a headless probe needs focus emulation to see it). */
  .dash-side-link:hover .dash-side-label,
  .dash-side-link:focus-visible .dash-side-label {
    opacity: 1;
  }
  /* A heading is a rule between the two lists: its words stay for the
     list it labels (aria-labelledby), out of sight. */
  .dash-side-heading {
    height: 1px;
    margin: 8px;
    overflow: hidden;
    background: var(--d-line);
    text-indent: 100%;
    white-space: nowrap;
  }
  .dash-side-live-note {
    display: none;
  }
  /* The off line on the rail: the icon, centred like every item, and the
     sentence as its tooltip on hover and on keyboard focus. Two sentences
     do not fit on one line beside a rail, so this one wraps at 260px, as
     the sites' bubble does. */
  .dash-side-live-off {
    justify-content: center;
    align-items: center;
    width: 44px;
    min-height: 40px;
    margin: 0 auto 4px;
    padding: 0;
  }
  .dash-side-live-off .dash-side-label {
    width: -moz-max-content;
    width: max-content;
    max-width: 260px;
    white-space: normal;
  }
  .dash-side-live-off:hover .dash-side-label,
  .dash-side-live-off:focus-visible .dash-side-label {
    opacity: 1;
  }
  /* The shop's line: the icon, centred like every other item, and the
     sentence as its tooltip — the address in it white like the rest. */
  .dash .dash-side-live .dash-side-live-link {
    align-items: center;
    overflow-wrap: normal;
  }
  /* One line, as wide as the sentence: a tooltip against a 44px link
     would otherwise shrink to its narrowest, and Chrome counts the
     address's <wbr>s as places to break even under nowrap. */
  .dash-side-live .dash-side-label {
    width: -moz-max-content;
    width: max-content;
  }
  .dash-side-live-where {
    display: inline;
    color: inherit;
  }
  /* The sites' lines, a second tooltip under the first on the same hover
     or focus. Positioned against the slot, which is the link's size on
     the rail; 36px is the first tooltip's foot (centred on a 40px link,
     one line tall) plus a gap. They are the link's description too
     (aria-describedby), so a screen reader hears them either way. */
  .dash-side-live {
    position: relative;
  }
  .dash-side-live-sites {
    position: absolute;
    top: 36px;
    left: calc(100% + 12px);
    z-index: 30;
    width: -moz-max-content;
    width: max-content;
    max-width: 260px;
    margin: 0;
    padding: 4px 8px;
    border-radius: 6px;
    background: var(--d-ink);
    color: #ffffff;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.12s;
  }
  .dash-side-live:hover .dash-side-live-sites,
  .dash-side-live-link:focus-visible ~ .dash-side-live-sites {
    opacity: 1;
  }
  .dash-side-nav {
    margin-bottom: 8px;
  }
}
@media (max-height: 759px) {
  @container dash-side (max-width: 100px) {
    .dash .dash-side-link {
      min-height: 34px;
    }
    .dash-side-heading {
      margin: 4px 8px;
    }
    .dash-brand {
      padding-bottom: 8px;
    }
  }
}
@media (max-height: 599px) {
  @container dash-side (max-width: 100px) {
    .dash-side-in {
      overflow-x: hidden;
      overflow-y: auto;
    }
  }
}
/* ---------- a phone: a strip and a drawer ----------
 *
 * Below 700px a 60px rail is a sixth of the screen for a list you open
 * twice a visit, so it goes: the page gets the whole width and a strip at
 * the top carries the name and a Menu button. The button is a link to
 * #dash-side, so :target opens the drawer with scripting off; the script
 * makes it a toggle (.dash-side-open on the root), closes it on Esc, an
 * outside press or a link, and gives focus back.
 *
 * The strip scrolls away with the page rather than sticking: the
 * previewing pages pin their preview at the top of a phone's screen, and
 * two things pinned there is one too many.
 */
@media (max-width: 700px) {
  /* Two rows here, the strip and the page (the sidebar is fixed, out of
     the flow). The rows are stated: left to `auto`, the shell's
     `min-height: 100vh` shares a short page's leftover height between
     them, and the strip grew to 183px on Collections at 375x800. */
  .dash-shell {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto 1fr;
  }
  .dash-strip {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
    padding: 8px 16px;
    background: var(--d-panel);
    border-bottom: 1px solid var(--d-line);
  }
  /* A control like any other: the 40px height, the body size. */
  .dash .dash-strip-menu {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    flex: 0 0 auto;
    height: var(--d-control-h);
    padding: 0 12px 0 8px;
    border: 1px solid var(--d-line);
    border-radius: 6px;
    color: var(--d-ink);
    font-size: var(--d-text-body);
    font-weight: 600;
    text-decoration: none;
  }
  .dash-strip-menu:focus-visible {
    outline: 2px solid var(--d-accent);
    outline-offset: 2px;
  }
  .dash-strip-name {
    min-width: 0;
    overflow: hidden;
    font-weight: 600;
    white-space: nowrap;
    text-overflow: ellipsis;
  }
  .dash-side {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    z-index: 70;
    width: min(300px, 86vw);
    height: auto;
    visibility: hidden;
    transform: translateX(-100%);
    transition: transform 0.2s ease, visibility 0s linear 0.2s;
  }
  /* :target is the no-script path only: the script takes over (and adds
     .dash-side-js) because a hash cannot be cleared without navigating. */
  :root:not(.dash-side-js) .dash-side:target,
  .dash-side-open .dash-side {
    visibility: visible;
    transform: none;
    transition: transform 0.2s ease;
  }
  /* Under the strip while the strip is on screen — the script measures
     where it ends (--dash-drawer-top) — so the Menu button that opened
     the drawer stays in sight, says it is open and closes it again. A
     drawer drawn over its own button left that button covered and
     unreachable. Once the page has scrolled the strip away, and with no
     script at all, 0: the drawer has its own close control. */
  .dash-side-open .dash-side {
    top: var(--dash-drawer-top, 0px);
  }
  /* The scrim: everything right of the drawer, dimmed. Part of the
     drawer's own box, so a press on it is a press "outside" the menu that
     reaches nothing underneath; the script closes on it. */
  :root:not(.dash-side-js) .dash-side:target::after,
  .dash-side-open .dash-side::after {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: 100%;
    width: 100vw;
    background: rgba(16, 24, 32, 0.38);
  }
  .dash .dash-side-close {
    display: grid;
    place-items: center;
    flex: 0 0 var(--d-control-h);
    height: var(--d-control-h);
    border-radius: 6px;
    color: var(--d-muted);
  }
  .dash-side-close:hover {
    background: var(--d-bg);
    color: var(--d-ink);
  }
  .dash-side-close:focus-visible {
    outline: 2px solid var(--d-accent);
    outline-offset: -2px;
  }
}
@media (prefers-reduced-motion: reduce) {
  .dash-side,
  .dash-side-label,
  .dash-side-live-sites {
    transition: none;
  }
}
/* The page's side gutter is 24px, and 16px on a tablet and a phone (the
   one tablet breakpoint, 899px, where the split stacks too). The phone's
   strip uses the same 16, so its Menu button lines up with the heading
   under it. 24 and not 32: at 900 every pixel of gutter comes off the
   control rail, which is already clamped to leave the preview its 480. */
.dash-main {
  min-width: 0;
  padding: 24px 24px 64px;
}

@media (max-width: 899px) {
  .dash-main {
    padding: 16px 16px 48px;
  }
}
.dash-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 24px;
}

.dash-head h1 {
  margin: 0;
  font-size: var(--d-text-page);
  line-height: 1.25;
}

/* More than one action by the heading: together at the right, not spread
   across the row by the heading's space-between. */
.dash-head-acts {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

/* A measure, not a width. A sentence that runs the whole of a wide page
   is a sentence you lose your place in — the width belongs to the tables
   and the fields, not to the prose. */
.dash-head p {
  margin: 8px 0 0;
  max-width: 86ch;
  color: var(--d-muted);
  font-size: var(--d-text-body);
}

/* The template picker: one tile per template, the one in use marked.
   Radios rather than a select, because choosing a look is a choice you
   want to see all of at once.

   164px is derived, not chosen. A tile has to hold the radio (13), the
   longest name ("Botanical", 67), the Live badge (40) and two 8px gaps —
   136px of content, 160 with the padding — or the badge wraps to a line
   of its own and makes that whole grid row half again as tall. At 164
   two columns need 336px inside the panel, which the 380px rail has and
   no narrower rail does; below that it is one wide column, where nothing
   can wrap at all. So there is no rail width, dragged or default, at
   which the badge wraps. */
.dash-templates {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(164px, 1fr));
  gap: 8px;
}

.dash-template {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px 8px;
  padding: 12px;
  border: 1px solid var(--d-line);
  border-radius: var(--d-radius);
  background: #ffffff;
  cursor: pointer;
}

/* Chrome gives a radio `margin: 3px 3px 0 5px`, which is 8px of the
   tile nobody asked for and nobody can see — and the 8px that pushed the
   badge onto a second line. */
.dash-template input {
  flex: 0 0 auto;
  margin: 0;
}

.dash-template:hover {
  border-color: var(--d-accent);
}

.dash-template.on {
  border-color: var(--d-accent);
  box-shadow: inset 0 0 0 1px var(--d-accent);
}

.dash-template-name {
  font-weight: 600;
}

/* "Live", as the word is written. Measured, the badge is 40px at 12px in
   sentence case, the 40 the tile's 164px budget (above) allows; every
   tile is 49px tall at the 380px rail. Finnish "Käytössä" is about 70
   and takes a line of its own, as it did in capitals (wider still). */
.dash-template-now {
  margin-left: auto;
  flex: 0 0 auto;
  padding: 1px 8px;
  border-radius: 999px;
  background: var(--d-accent);
  color: var(--d-accent-ink);
  font-size: var(--d-text-meta);
  font-weight: 600;
}

/* The section list: one row per section, an arrow pair, a switch and
   whatever copy that section owns. */
.dash-sections {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* The list's Save (and "See it") under its last row, not touching it. */
.dash-sections + .dash-btn,
.dash-sections + .dash-btn-o {
  margin-top: 12px;
}

.dash-section {
  display: grid;
  grid-template-columns: 32px 44px minmax(0, 1fr);
  gap: 12px;
  align-items: start;
  padding: 12px 0;
  border-top: 1px solid var(--d-line);
}

.dash-section:first-child {
  border-top: 0;
}

/* A list whose order is fixed (the Footer's sections) has no arrows, so
   no column for them: the switches line up with the panel's heading and
   notes instead of sitting 44px in. */
.dash-sections-fixed .dash-section {
  grid-template-columns: 44px minmax(0, 1fr);
}

.dash-section-move {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

/* One reorder arrow for every list that has them — home, product and
   seller page sections, categories, shops, promotion blocks, picked
   products and pinned sellers: 32 x 28. It was 32 x 22 on some lists and
   30 x 26 on others. */
.dash-section-move button,
.dash-picked-buttons button {
  width: 32px;
  height: 28px;
  padding: 0;
  border: 1px solid var(--d-line);
  border-radius: 4px;
  background: #ffffff;
  color: var(--d-muted);
  font: inherit;
  line-height: 1;
  cursor: pointer;
}

.dash-section-move button:hover,
.dash-picked-buttons button:hover {
  border-color: var(--d-accent);
  color: var(--d-accent);
}

.dash-section-move button:focus-visible,
.dash-picked-buttons button:focus-visible {
  outline: 2px solid var(--d-accent);
  outline-offset: 1px;
}

/* A row's name: the body size at a label's weight, as a template's name
   and a promotion's title are. */
.dash-section-body > strong {
  display: block;
  font-weight: 600;
}

.dash-section-body > .dash-note {
  display: block;
}

/* A row that will not be listed: the Shops tab's "Hide from shop list" and
   the Categories tab's switch. Greyed, so the list reads the way the
   storefront will. The Shops tab used this class long before it had a
   rule, so ticking the box there greyed nothing. */
.dash-section-off > .dash-section-body > strong,
.dash-section-off > .dash-section-body > .dash-note {
  opacity: 0.45;
}

/* A promotion's row in a page's order (round 9, item 7), and a part with no
   switch (the Category page's): an icon where the switch would be, so the
   names line up with the sections'. The promotion row's link goes to the
   block in Promotions; its "Promotion" mark sits beside the name. */
.dash-section-promo-mark {
  display: flex;
  justify-content: center;
  padding-top: 2px;
  color: var(--d-muted);
}

.dash-section-promo .dash-mark {
  display: inline-block;
  margin: 2px 4px 0 0;
}

.dash-section-promo-edit {
  display: inline-block;
  margin-top: 2px;
  font-size: var(--d-text-meta);
}

/* "Edit in Promotions" here and "Change its place on …" on a block's card:
   links with a class of their own, so the dashboard's in-sentence link
   rule (:where(.dash) a:not([class])) does not reach them and they came out
   in the browser's blue. The same colour and underline as that rule. */
.dash-section-promo-edit,
.dash-promo-place {
  color: var(--d-accent);
  text-underline-offset: 2px;
}

/* A row kept in the order but not shown (Home page's Promotions row, for a
   shop while it is on): the grid above would otherwise beat [hidden]. */
.dash-section[hidden] {
  display: none;
}

/* Arrived at from a block's card in Promotions (#row-promo_<id>): the row
   says which it is for a moment's glance, without moving anything. */
.dash-section:target {
  margin: 0 -8px;
  padding-right: 8px;
  padding-left: 8px;
  border-radius: 6px;
  background: #fff8e6;
}

/* The Categories tab: each level of sub-categories is a row of its own
   under its parent, the full width of it, indented by a rule. A level
   costs only its indent; inside the name column it also gave up the
   parent's arrows and switch. A hidden parent greys everything under it,
   which is what the storefront does with it. */
.dash-cat-children {
  grid-column: 1/-1;
  margin: 4px 0 0 44px;
  padding-left: 12px;
  border-left: 2px solid var(--d-line);
}

.dash-cat-children > .dash-section {
  padding: 8px 0;
}

.dash-section-off .dash-cat-children {
  opacity: 0.5;
}

/* A phone gives each level less indent and a tighter gap, never smaller
   controls: the columns are the arrows' 32 and the switch's 44 at every
   level (they were 28 and 40, which the 32px arrow and the 44px switch
   stuck out of). */
@media (max-width: 560px) {
  .dash-cat-children {
    margin-left: 8px;
    padding-left: 8px;
  }
  .dash-cat-children > .dash-section {
    gap: 8px;
  }
}
/* A switch that is a checkbox underneath, so it works without
   JavaScript and reads as a checkbox to a screen reader. */
.dash-switch {
  position: relative;
  display: block;
  width: 44px;
  height: 24px;
  margin-top: 2px;
}

.dash-switch input {
  position: absolute;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.dash-switch span {
  position: absolute;
  inset: 0;
  border-radius: 999px;
  background: #c9ced6;
  transition: background 0.15s;
  pointer-events: none;
}

.dash-switch span::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #ffffff;
  transition: transform 0.15s;
}

.dash-switch input:checked + span {
  background: var(--d-accent);
}

.dash-switch input:checked + span::after {
  transform: translateX(20px);
}

.dash-switch input:focus-visible + span {
  outline: 2px solid var(--d-accent);
  outline-offset: 2px;
}

/* A field inside a row, 12 under whatever is above it. Doubled up with
   .dash-field, because .dash-field's own `margin: 0 0 12px` comes later
   in this file and took the top margin away: a row's first field sat
   straight on the sentence above it. */
.dash-field-inline,
.dash-field.dash-field-inline {
  margin: 12px 0 0;
  max-width: 560px;
}

/* A field's name has one weight wherever the field is. */
.dash-field-inline > span:first-child {
  font-weight: 600;
}

.dash-sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* Two panels side by side, where the page has the width for it and the
   two belong together — what you add beside what is synced, the list
   beside the picker, the words beside the picture. `auto-fit` with a
   real minimum is what makes it one column on a phone without a second
   rule: below about 800px the second track cannot be built, so there is
   not one. The minimum is `min(360px, 100%)`, as on .dash-examples: a
   phone's column is 343px, and a bare 360px pushed every panel 17px past
   it, flush with the screen's right edge and the page 1px sideways
   (Settings, Footer, Featured sellers, Promotions at 375).

   `align-items: start` so a short panel does not stretch to the height
   of a tall one and sit half empty. */
.dash-cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(360px, 100%), 1fr));
  gap: 0 var(--d-gap);
  align-items: start;
}

/* A table is the one thing on these pages allowed to be wider than the
   page, so it gets a box of its own to be wider inside. Without it a
   375px screen scrolled sideways on Sellers, Collections and Reviews —
   which it did before any of this too; six columns of real data do not
   fit on a phone however they are sized, and the honest answer is to let
   the table scroll rather than to crush the columns until it fits. */
.dash-tablewrap {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
}

/* A plain table for the lists: sellers, collections, reviews.

   Column widths are set by the cells, not by the browser sharing the
   width equally: a column holding "0" and a column holding a tagline
   both got a fifth of 1,144px, which is how a wider page turns into a
   sparser one instead of a better one. `.dash-col-tight` shrinks to its
   content and `.dash-col-wide` takes what is left. */
.dash-table {
  width: 100%;
  border-collapse: collapse;
}

.dash-table th,
.dash-table td {
  padding: 12px 16px 12px 0;
  border-bottom: 1px solid var(--d-line);
  text-align: left;
  vertical-align: top;
}

/* A column's name is a label: the label's size and weight, muted, and in
   the case it is written in. */
.dash-table th {
  font-size: var(--d-text-note);
  font-weight: 600;
  color: var(--d-muted);
}

.dash-table tr:last-child td {
  border-bottom: 0;
}

/* 1% rather than 0: a percentage is resolved against the table and then
   raised to fit the content, which is the shrink-to-fit every browser
   agrees on. */
.dash-table .dash-col-tight {
  width: 1%;
  white-space: nowrap;
}

/* A column of counts: right-aligned, in digits of one width so they line
   up (Insights' shared pages). */
.dash-table .dash-col-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Insights' numbers (partials/shared_links): a row of tiles, each a label
   over its figure — four across on a desktop, two by two in a phone's
   311px panel. Wrapped by the grid, never squeezed: `min()` so a column
   narrower than one tile gets one a row rather than a tile wider than the
   screen. The figure keeps the face's own proportional digits — a lone
   number set in tabular ones looks loose. */
.dash-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(136px, 100%), 1fr));
  gap: 12px;
  margin: 12px 0;
}

.dash-stat {
  padding: 12px 14px;
  border: 1px solid var(--d-line);
  border-radius: var(--d-radius);
  background: var(--d-panel);
}

.dash-stat dt {
  font-size: var(--d-text-note);
  color: var(--d-muted);
}

.dash-stat dd {
  margin: 4px 0 0;
  font-size: 28px;
  font-weight: 600;
  line-height: 1.15;
  color: var(--d-ink);
}

.dash-stat .dash-stat-sub {
  margin-top: 2px;
  font-size: var(--d-text-meta);
  font-weight: 400;
  line-height: 1.4;
  color: var(--d-muted);
}

/* Two by two on a phone, where a label may take two lines: each keeps room
   for two, so the figures in a row stand level. */
@media (max-width: 700px) {
  .dash-stat dt {
    min-height: 2.6em;
  }
}
/* No width at all, deliberately. `width: 100%` here drove every other
   column to min-content — "verified purchase" became three lines to buy
   slack for a cell that did not need it. Left alone, the auto algorithm
   shares what the tight columns did not take between the columns that
   have something to say, in proportion to how much they have to say,
   which is the answer this was reaching for. */
.dash-table .dash-col-wide {
  min-width: 30%;
}

/* A name column. Not `tight`, because a product title has no business
   being nowrap — that is how one long name makes the table wider than
   the page. And deliberately no `width`: a stated width sends the auto
   table algorithm towards min-content and wrapped "Hollantilaisia
   lastenkirjoja" to two lines while 200px sat unused two columns over.
   With only a cap, the column asks for its longest name, gets it up to
   320px, and `.dash-col-wide` still takes every pixel that is left. */
.dash-table .dash-col-name {
  max-width: 320px;
}

/* The last column is whatever acts on the row. Hard right, so the
   buttons line up with each other rather than with the text beside
   them. */
.dash-table .dash-col-act {
  width: 1%;
  padding-right: 0;
  white-space: nowrap;
  text-align: right;
}

/* Pages of a long list (Reviews, 50 a page). Laravel's own links —
   `Paginator::useBootstrap()` and resources/views/vendor/pagination — are
   Bootstrap's markup, and nothing on these pages loads Bootstrap, so they
   were a bulleted list. Drawn as a row of small buttons: 32px, the page
   you are on filled, the ends that go nowhere faded. It sits between two
   panels, so it keeps the panels' gap under it; the one above has its own. */
.dash .pagination {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin: 0 0 var(--d-gap);
  padding: 0;
  list-style: none;
}

.dash .page-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--d-control-h-small);
  height: var(--d-control-h-small);
  padding: 0 12px;
  border: 1px solid var(--d-line);
  border-radius: 6px;
  background: #ffffff;
  color: var(--d-ink);
  font-size: var(--d-text-note);
  font-weight: 600;
  text-decoration: none;
}

.dash a.page-link:hover {
  border-color: var(--d-accent);
  color: var(--d-accent);
}

.dash a.page-link:focus-visible {
  outline: 2px solid var(--d-accent);
  outline-offset: 2px;
}

.dash .page-item.active .page-link {
  border-color: var(--d-accent);
  background: var(--d-accent);
  color: var(--d-accent-ink);
}

.dash .page-item.disabled .page-link {
  color: var(--d-muted);
  opacity: 0.5;
}

/* A long synced field in a table cell: two lines, then an ellipsis. The
   whole of it is on the seller's own page; here it only has to say
   whether there is anything. */
.dash-clamp {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}

/* Small marks for "this is set" — a website, a social account. Quieter
   than a chip, which is a thing you click. */
.dash-marks {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 4px;
}

.dash-mark {
  padding: 1px 8px;
  border: 1px solid var(--d-line);
  border-radius: 999px;
  color: var(--d-muted);
  font-size: var(--d-text-meta);
  white-space: nowrap;
}

/* What the store itself has added to a synced row. */
.dash-added {
  display: flex;
  align-items: center;
  gap: 8px;
}

.dash-added-banner {
  flex: 0 0 auto;
  width: 96px;
  height: 40px;
  border-radius: 4px;
  background: var(--d-bg);
  -o-object-fit: cover;
     object-fit: cover;
}

.dash-table td .dash-note {
  display: block;
}

/* On a phone a list's rows are cards (Sellers, Collections, Reviews:
   .dash-table-stack). Scrolling a 783px table sideways inside a 309px
   box, with nothing to say it scrolls, cut every row's text at the edge
   and put its only button out of sight. Each cell is a line of the card
   under its column's name (data-label, the header's own words); a short
   value sits beside its name; the first cell is the card's title and the
   buttons take the card's width. The header row is still there for a
   screen reader, drawn nowhere. */
@media (max-width: 560px) {
  .dash-table-stack,
  .dash-table-stack tbody,
  .dash-table-stack tr,
  .dash-table-stack td {
    display: block;
    width: auto;
  }
  .dash-table-stack thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
  .dash-table-stack tr {
    padding: 12px 0;
    border-bottom: 1px solid var(--d-line);
  }
  .dash-table-stack tr:first-child {
    padding-top: 0;
  }
  .dash-table-stack tr:last-child {
    padding-bottom: 0;
    border-bottom: 0;
  }
  .dash-table-stack td,
  .dash-table-stack .dash-col-name,
  .dash-table-stack .dash-col-tight,
  .dash-table-stack .dash-col-wide,
  .dash-table-stack .dash-col-act {
    width: auto;
    max-width: none;
    min-width: 0;
    padding: 4px 0;
    border: 0;
    white-space: normal;
    text-align: left;
  }
  .dash-table-stack td[data-label]::before {
    content: attr(data-label);
    display: block;
    margin-bottom: 2px;
    color: var(--d-muted);
    font-size: var(--d-text-note);
    font-weight: 600;
  }
  .dash-table-stack .dash-col-tight[data-label]::before {
    display: inline;
    margin: 0 8px 0 0;
  }
  .dash-table-stack .dash-col-act {
    display: flex;
    gap: 8px;
    padding-top: 8px;
  }
  .dash-table-stack .dash-col-act form {
    flex: 1 1 0;
  }
  .dash-table-stack .dash-col-act .dash-btn-o {
    flex: 1 1 0;
    width: 100%;
  }
}
/* Footer's "What the bottom of your pages is showing" (a site's hosts).
   Two columns only where there is room for both: in the controls column
   (380px, or wider when dragged) the host, which does not wrap, took half
   the width and "What it shows" wrapped every word or two. Narrower than
   520px a row is the host over its words, the header row kept for a
   screen reader, as .dash-table-stack does on a phone. A container query
   rather than a media one, because the column's width is the owner's. */
.dash-hosts-wrap {
  container-type: inline-size;
}

@container (max-width: 519px) {
  .dash-table-hosts,
  .dash-table-hosts tbody,
  .dash-table-hosts tr,
  .dash-table-hosts td {
    display: block;
    width: auto;
  }
  .dash-table-hosts thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }
  .dash-table-hosts tr {
    padding: 12px 0;
    border-bottom: 1px solid var(--d-line);
  }
  .dash-table-hosts tr:first-child {
    padding-top: 0;
  }
  .dash-table-hosts tr:last-child {
    padding-bottom: 0;
    border-bottom: 0;
  }
  .dash-table-hosts td,
  .dash-table-hosts .dash-col-name,
  .dash-table-hosts .dash-col-wide {
    max-width: none;
    min-width: 0;
    padding: 0;
    border: 0;
  }
  .dash-table-hosts .dash-col-name {
    margin-bottom: 4px;
    color: var(--d-muted);
    font-size: var(--d-text-note);
    font-weight: 600;
    overflow-wrap: anywhere;
  }
}
.dash-chip {
  display: inline-block;
  margin: 0 8px 8px 0;
  padding: 4px 12px;
  border: 1px solid var(--d-line);
  border-radius: 999px;
  background: #ffffff;
  color: var(--d-ink);
  font-size: var(--d-text-note);
  text-decoration: none;
}

a.dash-chip:hover {
  border-color: var(--d-accent);
  color: var(--d-accent);
}

/* An ordered list you can reorder: chosen products, pinned sellers. */
.dash-picked {
  margin: 0 0 16px;
  padding: 0;
  list-style: none;
  counter-reset: picked;
}

.dash-picked li {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 0;
  border-bottom: 1px solid var(--d-line);
  counter-increment: picked;
}

.dash-picked li::before {
  content: counter(picked);
  flex: 0 0 24px;
  color: var(--d-muted);
  font-size: var(--d-text-note);
  text-align: right;
}

.dash-picked li > span:first-of-type {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The arrows are the section rows' own size (.dash-section-move button). */
.dash-picked-buttons {
  display: flex;
  gap: 4px;
}

/* ---------- the bar ----------
 *
 * At the top of every page (partials/bar): what waits for Publish, and
 * Preview, Discard and Publish. Quiet when there is nothing to publish, so
 * it is not a permanent alarm; amber while there is.
 *
 * Sticky at the top of the page's column, on a ground of its own so the
 * page scrolls under it. The slot is the sticky thing and the bar the
 * card inside it, because the slot's ground has to reach past the card's
 * rounded corners. The layout's script measures the slot into
 * --dash-bar-h, and the split pages' pinned preview sits that far down
 * (below); 56px is the height of the one-line bar, for the first paint
 * and a page with no script. */
:root {
  --dash-bar-h: 56px;
}

.dash-bar-slot {
  position: sticky;
  top: var(--dash-top-h, 0px);
  z-index: 20;
  margin: -24px -24px 16px;
  padding: 12px 24px;
  background: var(--d-bg);
}

.dash-bar {
  position: relative;
  padding: 8px 12px 8px 16px;
  border: 1px solid var(--d-line);
  border-radius: var(--d-radius);
  background: var(--d-panel);
  font-size: var(--d-text-note);
}

.dash-bar.on {
  border-color: var(--d-warn-line);
  background: var(--d-warn-bg);
}

.dash-bar-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px 16px;
  flex-wrap: wrap;
  min-height: var(--d-control-h-small);
}

.dash-bar-says {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 12px;
  min-width: 0;
}

.dash-bar-line {
  color: var(--d-ink);
}

/* What this page does with a change, after the line, quieter. */
.dash-bar-mode {
  color: var(--d-muted);
}

.dash-bar-mode::before {
  content: "·";
  margin-right: 12px;
  color: var(--d-muted);
}

.dash-bar-status {
  color: var(--d-muted);
}

.dash-bar-status:empty {
  display: none;
}

.dash-bar-status .dash-btn-small {
  margin-left: 4px;
}

.dash-bar-buttons {
  display: flex;
  align-items: center;
  gap: 8px;
}

.dash-bar-buttons form {
  margin: 0;
}

.dash-bar-buttons button[disabled] {
  opacity: 0.45;
  cursor: default;
}

/* The list under Show more: each change, and the page it is on. In the
   bar's own flow, so it pushes the page down rather than covering it: as
   a drop-down over the page it hid the heading and the top of the first
   card, and with eleven changes a third of a phone. The bar grows by the
   list, the script measures it again (ResizeObserver) and the preview
   pinned under the bar moves down with it. The list scrolls inside
   itself past a third of the window. */
.dash-bar-row:has(.dash-more[open]) {
  /* The buttons stay level with the line, not halfway down the list. */
  align-items: flex-start;
}

.dash-bar-says:has(> .dash-more[open]) {
  /* Open, the line and its list take the room the buttons leave; sized
     by the list's longest line instead, they would push the buttons onto
     a row of their own. */
  flex: 1 1 260px;
}

.dash-bar .dash-more[open] {
  flex: 1 1 100%;
}

.dash-bar .dash-more[open] > .dash-more-body {
  margin: 6px 0 2px;
  padding: 6px 0 0;
  border-top: 1px solid var(--d-warn-line);
}

.dash-bar-changes {
  max-height: 33vh;
  margin: 0;
  padding: 0 0 0 18px;
  overflow: auto;
  overscroll-behavior: contain;
}

.dash-bar-changes li {
  padding: 1px 0;
  -moz-column-break-inside: avoid;
       break-inside: avoid;
}

/* Two columns where a line is short beside the room there is. */
@media (min-width: 1100px) {
  .dash-bar-changes {
    -moz-columns: 2 320px;
         columns: 2 320px;
    -moz-column-gap: 32px;
         column-gap: 32px;
  }
}
@media (max-width: 899px) {
  .dash-bar-changes {
    max-height: 22vh;
  }
}
/* A phone: the list may take up to 40% of the screen, scrolling inside
   itself, and while it is open the bar stops being pinned — a pinned bar
   that tall, with the pinned preview under it, would leave no page to
   scroll. The bar scrolls away with the page, and the script measures a
   bar that is not pinned as 0 so the preview pins to the top instead.
   Shut, the bar is pinned again. */
@media (max-width: 700px) {
  .dash-bar-changes {
    max-height: 40vh;
  }
  .dash-bar-slot:has(details[data-more][open]) {
    position: static;
  }
}
.dash-bar-changes a,
.dash-bar-ask-name a {
  color: var(--d-ink);
  font-weight: 600;
}

/* Also changed on the live shop: a question for each, before Publish. */
.dash-bar-asks {
  max-height: 40vh;
  margin: 8px 0 0;
  padding: 8px 0 0;
  border-top: 1px solid var(--d-warn-line);
  overflow: auto;
}

.dash-bar-asks-line {
  margin: 0 0 4px;
  color: var(--d-warn-ink);
  font-weight: 600;
}

.dash-bar-asks ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

.dash-bar-ask {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px 16px;
  padding: 6px 0;
}

.dash-bar-ask + .dash-bar-ask {
  border-top: 1px dashed var(--d-warn-line);
}

.dash-bar-ask-name {
  flex: 1 1 180px;
  min-width: 0;
}

.dash-bar-ask-values {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 12px;
  flex: 2 1 240px;
  min-width: 0;
  overflow-wrap: anywhere;
}

.dash-bar-ask-buttons {
  display: flex;
  gap: 8px;
}

.dash-bar-ask-buttons form {
  margin: 0;
}

@media (max-width: 899px) {
  .dash-bar-slot {
    margin: -16px -16px 12px;
    padding: 8px 16px;
  }
}
/* A phone: the line and the buttons on one row where they fit, and the
   Preview button only where the page has no preview of its own pinned
   under the bar already. */
@media (max-width: 560px) {
  .dash-bar {
    padding: 6px 8px 6px 12px;
  }
  .dash-bar-mode::before {
    content: none;
  }
  body.dash-split-page .dash-bar-preview {
    display: none;
  }
}
/* The sidebar's dot on a page with unpublished changes: amber, by the
   name, and on the rail by the icon's corner. */
.dash-side-dot {
  flex: 0 0 8px;
  width: 8px;
  height: 8px;
  margin-left: auto;
  border-radius: 50%;
  background: #d68a00;
}

.dash-side-dot[hidden] {
  display: none;
}

@container dash-side (max-width: 100px) {
  .dash-side-dot {
    position: absolute;
    top: 6px;
    right: 6px;
    margin: 0;
  }
}
/* ---------- the split: controls one side, preview the other ----------
 *
 * Below 900px this is one column, preview first. Above it, an explicit
 * two-column grid — the source order puts the preview first for the
 * phone, so the desktop places both by grid-column rather than relying
 * on it.
 *
 * **The page is an ordinary scrolling page and the preview is an
 * ordinary sticky sidebar.** It used to own the viewport: body and shell
 * at `height: 100vh; overflow: hidden`, and the controls column with a
 * scrollbar of its own. That kept the iframe permanently in view, and it
 * cost the thing people do without thinking — a wheel over the page
 * scrolled nothing unless the pointer happened to be inside the one box
 * that scrolled, and the browser's own scrollbar was gone. Now the whole
 * page scrolls, the wheel works wherever the pointer is, and the preview
 * follows down the column until the controls run out beneath it, which
 * is the behaviour every sidebar on the web has.
 *
 * The sticky element is the PANEL, not the column: a grid item stretched
 * to the row's height has nowhere to move, so the column stretches and
 * the panel inside it sticks.
 */
.dash-split {
  display: grid;
  /* minmax(0, 1fr), not the implicit `auto`: an auto grid track is sized
     to its max-content, and the preview iframe is deliberately 1280px
     wide (scaled down by transform, which does not change layout size).
     Left as auto, that 1280 pushed the single column past the viewport
     and the whole page scrolled sideways. */
  grid-template-columns: minmax(0, 1fr);
  gap: var(--d-gap);
}

/* Under 900px there is no room for two columns, so the preview goes
   above the controls — and is PINNED there.

   Measured at 375, the three arrangements cost this much scrolling:

     preview above, not pinned   see it: 112px   control -> preview: 1849px
     controls above, not pinned  see it: 1439px  control -> preview:  172px
     preview above, pinned       see it:   0px   control -> preview:    0px

   Both plain orders have one bad number, because the preview is a 480px
   object at one end of a 2,400px page: put it first and every control
   is a long way from it, put it last and it is a long way from the top.
   Pinning it answers both — the thing you are looking at while you work
   stays in front of you — and costs the top third of the screen, which
   on a page whose purpose is watching your shop change is what that
   third is for. */
@media (max-width: 899px) {
  /* One column, so there is nothing to divide. */
  .dash-split-grip {
    display: none;
  }
  .dash-split-preview {
    position: sticky;
    /* Under the bar, which is pinned above it (its measured height), and
       the top bar above that where it sticks (above 700px). */
    top: calc(var(--dash-top-h, 0px) + var(--dash-bar-h));
    z-index: 3;
    /* The panel is the pinned thing, so it needs a ground of its own:
       the controls scroll underneath it. */
    margin: 0 -16px;
    padding: 0 16px 8px;
    background: var(--d-bg);
  }
  .dash-split-preview .dash-panel {
    margin-bottom: 0;
    box-shadow: 0 6px 14px rgba(16, 24, 32, 0.08);
  }
  .dash-split-preview .dash-preview-frame iframe {
    /* A third of the screen, never less than a usable strip. */
    height: calc(38vh / var(--preview-scale, 1));
    min-height: calc(220px / var(--preview-scale, 1));
  }
  /* The bleed above matches .dash-main's own side padding, or the
     controls would show through the gap as they scroll under the pinned
     panel. Both change at this one breakpoint now; they used to change
     at 860 and 899, and the window between needed a bleed of its own. */
  /* The sentences under the frame are for a desktop, where there is
     room. Pinned on a phone they would be 60-150px of the screen spent
     explaining the thing they cover — both of them: the frame's own line
     and, where a site's block stands in front, the raw-block note. The
     old `:last-child` hid only the second and kept the first. */
  .dash-split-preview .dash-panel > .dash-note {
    display: none;
  }
}
@media (min-width: 900px) {
  /* How far from the top of the viewport the pinned panel sits, and how
     much of the viewport it may take. One pair of numbers, because the
     panel's `top` and its height have to agree or the bottom of the
     iframe falls off the screen. */
  body.dash-split-page {
    /* Below the bar, which sticks at the top of the column too, and the
       top bar above it. */
    --dash-sticky-top: calc(var(--dash-top-h, 0px) + var(--dash-bar-h) + 4px);
    --dash-sticky-gap: 16px;
  }
  .dash-split {
    /* The controls are a rail and the preview takes everything else. Not
       two proportional columns: the preview renders a 1280px page scaled
       to fit, so every pixel the controls do not need is a pixel of
       legibility — at 1200 a proportional split gave the preview 443px
       (34% scale) and the rail gives it 532 (42%), and the controls lose
       nothing they were using.

       --dash-rail is the owner's own width, dragged on the grip and kept
       in their browser.

       380px, up from the 340 it was while the page carried a 232px left
       rail the first time: 40px buys the template picker a second column
       that cannot wrap its badge (see .dash-templates). The sidebar is
       back since, at 216px from 1100 up and 60 below, and the preview
       pays for it — the measured widths are in the note on the shell at
       the top of this file. The rail did not shrink to pay it back: 380
       is what the controls need, and the clamps below already give way
       to the preview's 480px minimum where the window is narrow. */
    grid-template-columns: var(--dash-rail, 380px) 5px minmax(0, 1fr);
    /* 14, off the spacing scale on purpose: draft_js's clamp (GAP = 14)
       does this arithmetic too, and at 16 the preview came out 476px at
       900, under the 480 the clamp promises. Change both together. */
    gap: 0 14px;
    /* Stretch, not start: the grip has to reach the full height of the
       row and the preview column has to be tall enough for the panel
       inside it to have somewhere to stick. */
    align-items: stretch;
  }
  .dash-split-grip {
    grid-column: 2;
    grid-row: 1;
    position: relative;
    align-self: stretch;
    width: 5px;
    border-radius: 3px;
    background: var(--d-line);
    cursor: col-resize;
    transition: background 0.12s;
  }
  /* The hit area is wider than the line, because a 5px target is a
     5px target however it is drawn. */
  .dash-split-grip::before {
    content: "";
    position: absolute;
    inset: 0 -7px;
  }
  .dash-split-grip:hover,
  .dash-split-grip:focus-visible,
  .dash-split-grip.dragging {
    background: var(--d-accent);
    outline: none;
  }
  /* While dragging, nothing else should take the pointer — least of all
     the iframe, which would swallow it the moment the cursor crossed
     into the preview. */
  body.dash-dragging,
  body.dash-dragging * {
    cursor: col-resize !important;
    -webkit-user-select: none;
       -moz-user-select: none;
            user-select: none;
  }
  body.dash-dragging iframe {
    pointer-events: none;
  }
  /* An ordinary column now. No scrollbar of its own, nothing capped to
     the viewport: it is as tall as its fields and the page scrolls. */
  .dash-split-controls {
    grid-column: 1;
    grid-row: 1;
    padding-bottom: 24px;
  }
  .dash-split-preview {
    grid-column: 3;
    grid-row: 1;
  }
  /* The sidebar. A DEFINITE height, not a max-height: the iframe's own
     height is a percentage of this box divided by its scale, and a
     percentage needs something definite to be a percentage of. That
     definiteness is the one thing the old viewport-owning layout
     provided that a plain scrolling page does not, so it is stated here
     rather than inherited from a flex chain — see the note on
     .dash-preview-frame iframe. The scaled WIDTH never depended on it:
     fit() reads the pane's clientWidth, which is a layout width either
     way. */
  .dash-split-preview .dash-panel {
    position: sticky;
    top: var(--dash-sticky-top);
    display: flex;
    flex-direction: column;
    height: calc(100vh - var(--dash-sticky-top) - var(--dash-sticky-gap));
    margin-bottom: 0;
  }
  .dash-split-preview .dash-preview-frame {
    flex: 1 1 auto;
    min-height: 0;
  }
  .dash-split-preview .dash-preview-frame iframe {
    height: calc(100% / var(--preview-scale, 1));
    min-height: 0;
  }
  /* The line under the frame explains the pane; with the frame filling
     the column it would push the frame out of it. Only the frame's own
     line: the raw-block note after it (a site's block standing in front
     of the fields) is what this pane must say, and `:last-child` hid
     exactly that one whenever it was there. */
  .dash-split-preview .dash-preview-frame + .dash-note {
    display: none;
  }
}
/* ---------- full size ----------
 *
 * The preview takes the window and the controls step aside. Nothing is
 * re-rendered and nothing is reloaded: the same element is moved, so the
 * draft on screen and the scroll position of the controls behind it are
 * where they were when the button was pressed.
 *
 * `position: fixed` and not a dialog, because the iframe must keep its
 * document — showModal() on an ancestor would not reload it, but moving
 * the element in the DOM would, and a <dialog> wrapper is a move.
 */
body.dash-preview-full-on {
  overflow: hidden;
}

body.dash-preview-full-on .dash-split-preview {
  position: fixed;
  inset: 0;
  z-index: 60;
  margin: 0;
  padding: 0;
  background: var(--d-bg);
}

/* The panel is the window, and the frame fills what its head leaves, at
   every width. Above 900px the sidebar rules already made the panel a
   column with the frame flexing into it; below, the pinned strip's
   `38vh` frame came along into full size, and a phone showed a 340px
   preview at the top of an otherwise empty screen. */
body.dash-preview-full-on .dash-split-preview .dash-panel {
  position: static;
  display: flex;
  flex-direction: column;
  height: 100vh;
  margin: 0;
  border: 0;
  border-radius: 0;
  box-shadow: none;
}

body.dash-preview-full-on .dash-split-preview .dash-preview-frame {
  flex: 1 1 auto;
  min-height: 0;
}

body.dash-preview-full-on .dash-split-preview .dash-preview-frame iframe {
  height: calc(100% / var(--preview-scale, 1));
  min-height: 0;
}

/* The rest of the page is still there, still scrolled where it was, and
   out of the way — hidden from a screen reader too, since it cannot be
   reached while the preview is over it. The sidebar and the phone's strip
   with it: both would otherwise be a way off a page nobody can see. */
body.dash-preview-full-on .dash-top,
body.dash-preview-full-on .dash-side,
body.dash-preview-full-on .dash-strip,
body.dash-preview-full-on .dash-head,
body.dash-preview-full-on .dash-bar-slot,
body.dash-preview-full-on .dash-split-controls,
body.dash-preview-full-on .dash-split-grip {
  visibility: hidden;
}

.dash-preview-full {
  margin-left: 4px;
}

/* The preview's language, in the dashboard's chrome rather than inside
   the shop. Small and quiet: it is a way of checking, not a setting — so
   the small control's height, beside the small Desktop / Phone buttons. */
.dash-preview-lang select {
  height: var(--d-control-h-small);
  padding: 0 8px;
  border: 1px solid var(--d-line);
  border-radius: 6px;
  background: #ffffff;
  color: var(--d-ink);
  font: inherit;
  font-size: var(--d-text-note);
}

/* The block a store writes for itself, as the front page draws it. */
.dash-commercial-note {
  margin-top: 12px;
}

/* The preview pane: the real store page in an iframe. */
.dash-preview-head {
  display: flex;
  align-items: center;
  gap: 8px 12px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}

.dash-preview-head h2 {
  margin: 0;
  font-size: var(--d-text-heading);
  line-height: 1.3;
}

/* "Back to preview": only while the frame shows another page of the shop
   than the one the pane opened on (partials/preview_nav_js). Beside the
   heading, where the eye goes when the frame has changed. */
.dash-preview-back[hidden] {
  display: none;
}

/* What a click in the preview did when it did not happen in the frame
   (a new tab, or nothing): one quiet line under the note, for a moment. */
.dash-preview-said {
  margin-top: 4px;
  color: var(--d-ink);
}

.dash-preview-said[hidden] {
  display: none;
}

.dash-preview-sizes {
  display: flex;
  gap: 4px;
  margin-left: auto;
}

.dash-preview-sizes button.on {
  background: var(--d-accent);
  color: var(--d-accent-ink);
}

/* `width: 100%` because the panel around it is a flex column wherever the
   frame fills the height (beside the controls, and in full size), and a
   flex item with auto side margins — the phone frame's centring — shrinks
   to its content, which is the 390px iframe: in full size on a phone the
   frame came out 390 wide in a 343px panel. */
.dash-preview-frame {
  width: 100%;
  overflow: hidden;
  border: 1px solid var(--d-line);
  border-radius: var(--d-radius);
  background: #ffffff;
}

/* The iframe is rendered at --preview-w (a real viewport width) and
   scaled by --preview-scale to fit the column, so "Desktop" shows the
   desktop layout even in a 445px-wide column. The height is divided by
   the same scale, so the scaled result fills the box exactly. Both
   properties are set by the layout's script; the fallbacks here are what
   a visitor without JavaScript gets, which is the old behaviour — an
   iframe as wide as its column. */
.dash-preview-frame iframe {
  display: block;
  width: var(--preview-w, 100%);
  height: calc(70vh / var(--preview-scale, 1));
  min-height: calc(480px / var(--preview-scale, 1));
  border: 0;
  transform: scale(var(--preview-scale, 1));
  transform-origin: top left;
}

/* Phone width, centred, so the frame itself stays where it is. */
.dash-preview-frame.phone {
  max-width: 390px;
  margin: 0 auto;
}

/* ---------- the examples gallery ---------- */
/* Two columns at most, never three or four. Six cards three-across is a
   contact sheet; two-across each card is wide enough to draw a shop in
   and read the words beside it. One column below 720px. */
.dash-examples {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 340px), 1fr));
  gap: var(--d-gap);
  margin: 0 0 var(--d-gap);
  max-width: 1080px;
}

@media (min-width: 720px) {
  .dash-examples {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
.dash-example {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--d-panel);
  border: 1px solid var(--d-line);
  border-radius: var(--d-radius);
}

/* ---------- the miniature ----------
 *
 * A shop drawn from the example's own token values: its ground, ink,
 * accent and surface, its own two fonts, its corner radii, its card
 * treatment, where its logo sits and where its icons sit. Every value
 * arrives as a custom property on the element, put there by the view
 * from StoreExample::swatch(), which reads StoreTheme::PRESETS — so a
 * card cannot show a colour, a face or a radius the template has not
 * got.
 *
 * Not an iframe: six live renders for one tab load. Not a screenshot:
 * a file to keep in step with a constant, wrong the first time a
 * palette moved.
 */
.dash-example-shop {
  padding: 12px;
  background: var(--x-bg);
  color: var(--x-ink);
  font-family: var(--x-font);
  font-size: 11px;
  line-height: 1.35;
  border-bottom: 1px solid var(--d-line);
  overflow: hidden;
}

.dash-x-utilbar {
  display: flex;
  justify-content: flex-end;
  gap: 5px;
  margin: -12px -12px 8px;
  padding: 5px 12px;
  background: var(--x-surface);
}

.dash-x-utilbar span {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--x-ink);
  opacity: 0.38;
}

.dash-x-head {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 8px;
}

.dash-x-head-logo-centred {
  flex-direction: column;
  gap: 6px;
}

.dash-x-logo {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: var(--x-head);
  font-size: 15px;
  font-weight: 700;
}

.dash-x-mark {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--x-brand);
}

.dash-x-icons {
  display: flex;
  gap: 5px;
  margin-left: auto;
}

.dash-x-head-logo-centred .dash-x-icons {
  margin: 0;
}

.dash-x-icons span {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--x-ink);
  opacity: 0.38;
}

.dash-x-nav {
  display: flex;
  gap: 5px;
  margin-bottom: 10px;
  overflow: hidden;
}

.dash-x-nav span {
  padding: 2px 7px;
  border-radius: var(--x-pill);
  background: var(--x-surface);
  font-size: 10px;
  white-space: nowrap;
}

.dash-x-nav span.on {
  background: var(--x-accent);
  color: var(--x-bg);
}

.dash-x-hero {
  display: block;
  margin-bottom: 10px;
  padding: 12px;
  border-radius: var(--x-radius-lg);
  background: var(--x-surface);
}

.dash-x-title {
  display: block;
  font-family: var(--x-head);
  font-size: 19px;
  line-height: 1.15;
  font-weight: 700;
}

.dash-x-text {
  display: block;
  margin: 4px 0 8px;
  opacity: 0.72;
}

.dash-x-btn {
  display: inline-block;
  padding: 4px 10px;
  border-radius: var(--x-radius);
  background: var(--x-accent);
  color: var(--x-bg);
  font-size: 10px;
  font-weight: 600;
}

.dash-x-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 7px;
}

.dash-x-card {
  display: block;
  min-width: 0;
}

/* A fixed height, not the shop's 4:5. The miniature is about the shape
   of a card, not its proportions, and 4:5 of a 160px column is 200px of
   empty tint before the words start. */
.dash-x-photo {
  display: block;
  height: 62px;
  margin-bottom: 4px;
  border-radius: var(--x-radius);
  background: var(--x-surface);
}

.dash-x-name {
  display: block;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: 10px;
}

.dash-x-price {
  display: block;
  font-size: 10px;
  font-weight: 700;
}

/* The five card treatments, as the shop draws them. */
.dash-x-cards-boxed .dash-x-card {
  padding: 5px;
  border: 1px solid var(--x-ink);
  border-radius: var(--x-radius);
  border-color: color-mix(in srgb, var(--x-ink) 18%, transparent);
}

.dash-x-cards-elevated .dash-x-card {
  padding: 5px;
  border-radius: var(--x-radius);
  background: #ffffff;
  box-shadow: 0 3px 10px rgba(16, 24, 32, 0.14);
}

.dash-x-cards-soft .dash-x-card {
  padding: 5px;
  border-radius: var(--x-radius-lg);
  background: var(--x-surface);
}

.dash-x-cards-soft .dash-x-photo {
  background: var(--x-bg);
}

/* Editorial: the words over the photo, at its foot. */
.dash-x-cards-editorial .dash-x-card {
  position: relative;
}

/* Editorial puts white words over the photo, which works on a real
   photo and not on a pale tint — so the miniature's stand-in is ink at
   a low opacity rather than the surface colour. */
.dash-x-cards-editorial .dash-x-photo {
  height: 82px;
  margin: 0;
  background: color-mix(in srgb, var(--x-ink) 62%, var(--x-surface));
}

.dash-x-cards-editorial .dash-x-name,
.dash-x-cards-editorial .dash-x-price {
  position: absolute;
  left: 4px;
  color: #ffffff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.7);
}

.dash-x-cards-editorial .dash-x-name {
  bottom: 13px;
}

.dash-x-cards-editorial .dash-x-price {
  bottom: 2px;
}

.dash-example-body {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  padding: 16px;
}

.dash-example-body > h2 {
  margin: 0 0 4px;
  font-size: var(--d-text-heading);
  line-height: 1.3;
}

.dash-example-body > .dash-note {
  margin: 0 0 12px;
}

.dash-example-act {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: auto;
  padding-top: 12px;
}

/* ---------- the similar-products switches ---------- */
.dash-match {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 8px 16px;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--d-line);
}

/* A checkbox or a radio and what it says. The option is a control, so its
   words are the body size; its name, where it has one, a label's weight;
   the sentence under it a note. The box is centred on the first line. */
.dash-check {
  display: flex;
  align-items: start;
  gap: 8px;
  font-size: var(--d-text-body);
}

.dash-check input {
  flex: 0 0 auto;
  margin: 5px 0 0;
  width: auto;
}

.dash-check strong {
  font-weight: 600;
}

.dash-check .dash-note {
  display: block;
  font-weight: 400;
}

/* A section's own setting under its row (round 9, partials/section_option):
   text width, what New this week does when nothing is new. A fieldset for
   the group's name, drawn as a field of the row: no box, the name as a
   field's name, the choices one under the other, each choice's note on
   its own line under its words (.dash-check .dash-note is a block). */
.dash-option {
  display: grid;
  gap: 6px;
  min-width: 0;
  max-width: 560px;
  margin: 12px 0 0;
  padding: 0;
  border: 0;
}

.dash-option legend {
  margin: 0 0 2px;
  padding: 0;
  font-size: var(--d-text-note);
  font-weight: 600;
}

.dash-option .dash-check {
  font-size: var(--d-text-note);
}

.dash-option .dash-check input {
  margin-top: 2px;
}

.dash-option .dash-check .dash-note {
  margin-top: 1px;
}

/* The Categories tab's Menu panel: the two depths, then Unfold under
   them, greyed (.dash-section-off) while the top level alone is chosen. */
.dash-menu-depth {
  display: grid;
  gap: 8px;
  margin: 0 0 12px;
  max-width: 90ch;
}

.dash-menu-unfold {
  max-width: 90ch;
}

.dash-menu-unfold.dash-section-off {
  opacity: 0.5;
}

/* Under the greyed box, not greyed with it: what makes it work. In line
   with the box's words, past the box itself. `p.` outranks the panel's
   own note margin (.dash-panel > .dash-note), which comes later. */
.dash-panel > p.dash-menu-unfold-off {
  max-width: 90ch;
  margin: 4px 0 0 21px;
}

/* The control rail has no sizes of its own. It used to: 12px labels,
   15px panel headings (so the Preview heading beside it was the larger),
   inputs 2-6px shorter and panels 2px closer than on every other page.
   The scale is the same inside the split and out; fields are 12 apart
   everywhere, between the rail's 10 and the other pages' 14. */
/* ---------- Settings: parts, one form each ----------
   Each part is a heading, sometimes a sentence, and its own form and
   Save: nothing on the page waits for anything else on it. The rule
   between parts is what says "this Save is not that one". */
.dash-settings {
  margin: 0 0 32px;
}

.dash-settings + .dash-settings {
  padding-top: 24px;
  border-top: 1px solid var(--d-line);
}

/* A part's heading is a panel heading's size; the panels inside a part
   take the step down (.dash-panel > h3). */
.dash-settings-heading {
  margin: 0 0 4px;
  font-size: var(--d-text-heading);
  line-height: 1.3;
}

.dash-settings-heading + .dash-panel,
.dash-settings-heading + form {
  margin-top: 12px;
}

.dash-settings-intro {
  margin: 0 0 16px;
  max-width: 90ch;
}

.dash-panel.dash-settings-after {
  margin-top: var(--d-gap);
}

/* The language: a select and its button on one line, the select no wider
   than a language name needs. Its name is the part's heading. */
.dash-settings-lang {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 0;
}

.dash-settings-lang select {
  width: auto;
  min-width: 220px;
  max-width: 100%;
  height: var(--d-control-h);
  padding: 0 12px;
  border: 1px solid var(--d-line);
  border-radius: 6px;
  background: #ffffff;
  color: var(--d-ink);
  font: inherit;
}

/* ---------- panels, forms, controls ---------- */
/* 16 in, 16 apart, on every page and in the control rail alike. */
.dash-panel {
  margin: 0 0 var(--d-gap);
  padding: var(--d-pad);
  background: var(--d-panel);
  border: 1px solid var(--d-line);
  border-radius: var(--d-radius);
}

/* A panel's heading, one size wherever the panel is: the control rail's
   were 15px beside a 17px Preview, and a heading row's (.dash-panel-head)
   fell back to the browser's 22.5. */
.dash-panel > h2,
.dash-panel-head h2 {
  margin: 0 0 4px;
  font-size: var(--d-text-heading);
  line-height: 1.3;
}

/* A panel inside a headed part (Settings), and a part inside a panel
   (Promotions' category pages): one step down, the body size in bold. */
.dash-panel > h3 {
  margin: 0 0 4px;
  font-size: var(--d-text-body);
  line-height: 1.4;
}

/* A count or a word beside a heading is a note, not part of the heading:
   its own size and weight. */
.dash-panel > h2 > .dash-note,
.dash-panel > h3 > .dash-note,
.dash-panel-head h2 > .dash-note {
  margin-left: 4px;
  font-weight: 400;
}

.dash-panel > .dash-note {
  margin: 0 0 16px;
  max-width: 90ch;
}

/* The panel's padding is its bottom edge; the last thing in it adds
   nothing to it (a note's 16 or a field's 12 made the foot 28-32). */
.dash-panel > :last-child,
.dash-panel > form:last-child > :last-child {
  margin-bottom: 0;
}

/* A heading straight over a field (Design's Layout) gets the gap a note
   would have left, not the 4px that keeps a note close to its heading. */
.dash-panel > h2 + .dash-field,
.dash-panel > h3 + .dash-field {
  margin-top: 12px;
}

.dash-note {
  color: var(--d-muted);
  font-size: var(--d-text-note);
}

/* A field: its name, the control, and the note under it. One spacing
   everywhere — 12 between fields, 4 between a name and its control. */
.dash-field {
  display: block;
  margin: 0 0 12px;
}

.dash-field > span {
  display: block;
  margin-bottom: 4px;
  font-size: var(--d-text-note);
  font-weight: 600;
}

/* The note under a control is a note: the rule above made it a second
   bold name (Settings' "Trimmed to 300 characters when shown.", every
   hint under a Home page field). */
.dash-field > .dash-note {
  margin: 4px 0 0;
  font-weight: 400;
}

/* A checkbox inside a field's label (Sign in's "Remember me", a
   collection's "Show it"): the words beside the box are the option, not
   a field's name. */
.dash-field > input[type=checkbox] ~ span {
  margin: 0;
  font-size: var(--d-text-body);
  font-weight: 400;
}

/* One height for every text input and select: 40px, the button's. */
.dash-field input[type=text],
.dash-field input[type=email],
.dash-field input[type=password],
.dash-field input[type=url],
.dash-field input[type=search],
.dash-field select,
.dash-field textarea {
  width: 100%;
  height: var(--d-control-h);
  padding: 0 12px;
  border: 1px solid var(--d-line);
  border-radius: 6px;
  background: #ffffff;
  color: var(--d-ink);
  font: inherit;
}

.dash-field textarea {
  height: auto;
  min-height: 92px;
  padding: 8px 12px;
  resize: vertical;
}

/* Fields in columns. The maximum matters as much as the minimum: with
   `1fr` and a 1,144px page, six fields became five columns of 200px and
   then one, which is neither a row nor a form. Bounded, they are as many
   360px columns as fit and the rest of the panel is margin — which is
   what a text field wants beside it. */
.dash-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 360px));
  gap: 0 var(--d-gap);
}

/* An author rule that sets `display` beats the UA stylesheet's
   `[hidden] { display: none }`, so the attribute is inert without this —
   the same trap the nav chevrons fell into. The autosave hides the
   form's submit button with it. */
.dash-btn[hidden],
.dash-btn-o[hidden] {
  display: none;
}

/* A button is 40px tall, a small one 32: the height is the line (22px)
   and the padding, so a label that wraps on a phone grows the button
   rather than spilling out of it. */
.dash-btn,
.dash-btn-o {
  display: inline-block;
  padding: 8px 16px;
  border: 1px solid var(--d-accent);
  border-radius: 6px;
  font: inherit;
  font-weight: 600;
  line-height: 22px;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
}

.dash-btn {
  background: var(--d-accent);
  color: var(--d-accent-ink);
}

.dash-btn-o {
  background: none;
  color: var(--d-accent);
}

.dash-btn-small {
  padding: 4px 12px;
  font-size: var(--d-text-note);
}

.dash-flash {
  margin: 0 0 var(--d-gap);
  padding: 12px 16px;
  border: 1px solid #bfe3cd;
  border-radius: var(--d-radius);
  background: #eaf7f0;
  color: #145c31;
}

.dash-errors {
  margin: 0 0 var(--d-gap);
  padding: 12px 16px;
  border: 1px solid #f0c4c1;
  border-radius: var(--d-radius);
  background: #fdeceb;
  color: var(--d-danger);
}

.dash-errors ul {
  margin: 0;
  padding-left: 16px;
}

/* A value the store does not own: shown, never editable, a field's
   height when it is one line. A synced address has no spaces to wrap at
   (the Home page's registration link ran 60px out of its box at 375 and
   at 1099), so it may break anywhere. */
.dash-readonly {
  min-height: var(--d-control-h);
  padding: 8px 12px;
  border: 1px dashed var(--d-line);
  border-radius: 6px;
  background: #fafbfc;
  color: var(--d-muted);
  line-height: 22px;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* "Synced from your account": a badge, in the words' own case. */
.dash-synced {
  display: inline-block;
  margin-left: 8px;
  padding: 1px 8px;
  border-radius: 999px;
  background: #eef1f5;
  color: var(--d-muted);
  font-size: var(--d-text-meta);
  font-weight: 600;
  line-height: 1.5;
}

/* ---------- Compare: two examples, rendered full size, side by side ----------
   The gallery answers "what are these six?"; this answers "which of these
   two?", which a miniature drawn from five tokens cannot. Everything here
   is about giving two real renders as much width as the screen has. */
/* The page keeps the gutters every other page has (24px, 16 on a small
   screen): with 16 here the heading and the panels jumped 8px left going
   from Start from an example to Compare. Only the foot is shorter, since
   the frames are the page. */
.dash-compare-page .dash-main {
  padding-bottom: 24px;
}

/* One wrapping row. The pickers first because they are what is being
   chosen, the page switcher next because it moves both, and the two
   switches after, where they read as settings rather than as choices. */
.dash-compare-bar {
  /* Sticky, so the controls are still there once you have scrolled the
     two shops up to fill the screen — which is the whole way this page
     is used. Without it, changing the page type means scrolling back up
     past a 180px note to reach the switcher. Under the top bar. */
  position: sticky;
  top: var(--dash-top-h, 0px);
  z-index: 3;
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: 12px 16px;
  padding: 12px 16px;
  margin-bottom: var(--d-gap);
  background: var(--d-panel);
  border: 1px solid var(--d-line);
  border-radius: var(--d-radius);
}

.dash-compare-pick {
  min-width: 200px;
  flex: 0 1 240px;
  margin: 0;
}

/* The page switcher: a real radio group, drawn as one control. */
.dash-compare-pages {
  display: flex;
  align-items: center;
  gap: 0;
  border: 1px solid var(--d-line);
  border-radius: 6px;
  padding: 0;
  margin: 0;
  overflow: hidden;
}

.dash-compare-pages legend {
  /* Announced, never drawn: the three labels say what the group is. */
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.dash-seg {
  position: relative;
  display: block;
}

/* The radio itself stays in the page — focusable, announced, and where a
   screen reader expects it — and is simply not painted. `opacity: 0` and
   not `display: none`, which would take it out of the tab order. */
.dash-seg input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

/* A control's height and size: with the group's 1px frame, 40px, level
   with the two pickers beside it. */
.dash-seg span {
  display: block;
  padding: 8px 16px;
  font-size: var(--d-text-body);
  font-weight: 600;
  line-height: 22px;
  color: var(--d-muted);
  border-left: 1px solid var(--d-line);
  white-space: nowrap;
}

.dash-seg:first-of-type span {
  border-left: 0;
}

.dash-seg input:checked + span {
  background: var(--d-accent);
  color: var(--d-accent-ink);
}

/* The focus ring belongs on the thing that is drawn, not on the invisible
   input: a ring around a 0-opacity box is a ring nobody sees. */
.dash-seg input:focus-visible + span {
  outline: 2px solid var(--d-accent);
  outline-offset: -2px;
}

.dash-compare-sync {
  margin: 0 0 8px;
  white-space: nowrap;
}

.dash-compare-go {
  margin-left: auto;
}

/* Two panes, equal width, and `minmax(0, 1fr)` rather than `1fr` so a
   1280px-wide render inside cannot push the grid past the page — the same
   trap the stacked draft preview hit. */
.dash-compare-panes {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--d-gap);
  align-items: stretch;
}

.dash-compare-pane {
  display: flex;
  flex-direction: column;
  min-width: 0;
  background: var(--d-panel);
  border: 1px solid var(--d-line);
  border-radius: var(--d-radius);
  overflow: hidden;
}

.dash-compare-head {
  padding: 12px 16px;
  border-bottom: 1px solid var(--d-line);
}

.dash-compare-head h2 {
  margin: 0;
  font-size: var(--d-text-heading);
  line-height: 1.3;
}

.dash-compare-head .dash-marks {
  margin: 8px 0 0;
}

/* The render. A window onto the page, both panes the same height, each
   scrolling inside itself — a shop page is some fourteen thousand pixels
   tall and two of them laid out in full would be a page you cannot hold
   two things in your head across. The height is stated against the
   viewport so both windows are always the same and always the tallest the
   screen allows. */
.dash-compare-frame {
  display: block;
  width: 100%;
  /* A guess at the chrome above the panes. `--dash-compare-h` is read
     first, but nothing sets it: the fit() that was to measure the bar
     and the pane's title row was never written, so this calc() is what
     every browser gets. */
  height: var(--dash-compare-h, calc(100vh - 260px - var(--dash-top-h, 0px)));
  min-height: 380px;
  border: 0;
  background: #ffffff;
}

.dash-compare-note {
  margin-top: var(--d-gap);
}

/* Below 900px the two stack. There is no arrangement in which two
   real-width renders sit side by side on a phone: half of 375px is 187,
   which is narrower than a single product card, so both panes would be
   showing the shop's one-column layout squeezed — two pictures of nothing
   rather than a comparison. Stacked, each pane is the full width of the
   screen and each render is honest for that width; the page switcher and
   the scroll lock still move both. */
@media (max-width: 899px) {
  .dash-compare-panes {
    grid-template-columns: minmax(0, 1fr);
  }
  .dash-compare-frame {
    height: var(--dash-compare-h, calc(100vh - 320px - var(--dash-top-h, 0px)));
    min-height: 380px;
  }
  .dash-compare-pick {
    flex: 1 1 100%;
  }
  .dash-compare-go {
    margin-left: 0;
  }
}
/* ---------- a site's raw HTML, read-only ----------
   Shown so an operator can see what is standing in front of the fields
   above it, and removed if that is what they want. Never edited here:
   raw HTML can carry a script, and a site login is issued for design. */
.dash-raw {
  max-height: 260px;
  overflow: auto;
  margin: 0 0 12px;
  padding: 12px 16px;
  background: #f6f7f9;
  border: 1px solid var(--d-line);
  border-radius: var(--d-radius);
  font: 12px/1.6 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  color: #3a404a;
  /* Long unbroken markup must not push the page sideways; it scrolls in
     its own box, the rule every wide thing here follows. */
  white-space: pre-wrap;
  word-break: break-word;
  -moz-tab-size: 2;
    -o-tab-size: 2;
       tab-size: 2;
}

.dash-raw:focus-visible {
  outline: 2px solid var(--d-accent);
  outline-offset: 2px;
}

.dash-panel-raw .dash-note {
  max-width: 90ch;
}

/* Clearing somebody else's markup is destructive and reads as it. The
   button's own height and shape, in the danger colour. */
.dash-btn-danger {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 16px;
  border: 1px solid var(--d-danger);
  border-radius: 6px;
  background: transparent;
  color: var(--d-danger);
  font: inherit;
  font-weight: 600;
  line-height: 22px;
  cursor: pointer;
}

.dash-btn-danger:hover {
  background: var(--d-danger);
  color: #ffffff;
}

.dash-btn-danger:focus-visible {
  outline: 2px solid var(--d-danger);
  outline-offset: 2px;
}

/* ---------- a column explained under its own heading ----------
   Two switches whose names promised more than they did. The definition
   list is the shape that fits: the term, then what it does and — as
   importantly — what it does not. */
/* The term at the body size and a label's weight, what it does as a
   note under it: the sizes every other name-and-note pair here has. */
.dash-explain {
  margin: 12px 0 16px;
  padding: 0;
}

.dash-explain dt {
  margin: 12px 0 4px;
  font-weight: 600;
  font-size: var(--d-text-body);
}

.dash-explain dt:first-child {
  margin-top: 0;
}

.dash-explain dd {
  margin: 0;
  max-width: 90ch;
  color: var(--d-muted);
  font-size: var(--d-text-note);
  line-height: 1.5;
}

/* A panel's own heading row: the title and one action on the right. */
.dash-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 4px;
}

.dash-panel-head h2 {
  margin: 0;
}

/* Printable QR cards (App\SellerShare). On screen a sheet of A6 cards; in
   print one card per A6 page, nothing else on it. */
.dash-qr-print {
  margin: 0;
  background: #e9e9e6;
}

.dash-qr-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 16px;
  font-size: var(--d-text-body);
  background: #fff;
  border-bottom: 1px solid #d6d6d2;
}

.dash-qr-says {
  flex: 1 1 240px;
}

.dash-qr-sheet {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  padding: 16px;
}

.dash-qr-card {
  box-sizing: border-box;
  width: 105mm;
  height: 148mm;
  max-width: 100%;
  padding: 10mm 8mm;
  background: #fff;
  border: 1px solid #d6d6d2;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  page-break-after: always;
  -moz-column-break-after: page;
       break-after: page;
}

.dash-qr-store {
  margin: 0 0 4mm;
  font-size: 12px;
  color: #555;
  min-height: 1.2em;
}

.dash-qr-name {
  margin: 0 0 6mm;
  font-size: 22px;
  line-height: 1.2;
  word-break: break-word;
}

.dash-qr-code svg {
  width: 60mm;
  height: 60mm;
  display: block;
}

.dash-qr-url {
  margin: 6mm 0 0;
  font-size: 11px;
  color: #333;
  word-break: break-all;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

@media print {
  @page {
    size: A6;
    margin: 0;
  }
  .dash-qr-print {
    background: #fff;
  }
  .dash-qr-toolbar {
    display: none;
  }
  .dash-qr-sheet {
    display: block;
    padding: 0;
  }
  .dash-qr-card {
    border: 0;
    width: 105mm;
    height: 148mm;
    margin: 0;
  }
  .dash-qr-card:last-child {
    page-break-after: auto;
    -moz-column-break-after: auto;
         break-after: auto;
  }
}
@media (max-width: 640px) {
  .dash-qr-card {
    height: auto;
    padding: 8mm 6mm;
  }
}
/* A note the operator should act on. */
.dash-note.dash-warn {
  color: var(--d-warn-ink);
  background: var(--d-warn-bg);
  border: 1px solid var(--d-warn-line);
  border-radius: 6px;
  padding: 8px 12px;
}

/* A fact about the page the operator cannot act on here — Footer's line
   when the shop's address shows the site's footer in place of its blocks:
   plain, on a quiet ground, not coloured as a warning. The same look as
   Promotions' line of that kind. */
.dash-note.dash-info {
  padding: 8px 12px;
  border: 1px solid var(--d-line);
  border-radius: 6px;
  background: #f6f7f9;
}

/* ---------- a note that is one line until asked ----------
 *
 * <details>: the line is the summary, the rest is the body. The toggle
 * word sits at the right of the line and swaps with the open state, so
 * nothing is scripted for it. A note somebody opened is rendered open by
 * the server for that login (App\Dashboard\Notes). */
.dash-more {
  margin: 0 0 12px;
  border: 1px solid var(--d-line);
  border-radius: 6px;
  background: var(--d-panel);
  font-size: var(--d-text-note);
  color: var(--d-muted);
}

.dash-more-warn {
  color: var(--d-warn-ink);
  background: var(--d-warn-bg);
  border-color: var(--d-warn-line);
}

.dash-more > summary {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 8px 12px;
  cursor: pointer;
  list-style: none;
}

.dash-more > summary::-webkit-details-marker {
  display: none;
}

.dash-more > summary:focus-visible {
  outline: 2px solid var(--d-accent);
  outline-offset: 2px;
  border-radius: 6px;
}

/* One line, cut with an ellipsis rather than wrapped: the point of the
   collapsed state is its height. */
.dash-more-line {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 600;
}

.dash-more[open] .dash-more-line {
  white-space: normal;
}

.dash-more-toggle {
  flex: 0 0 auto;
  /* First in the markup (the float below needs it there), after the line
     on screen. */
  order: 2;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.dash-more-hide,
.dash-more[open] .dash-more-show {
  display: none;
}

.dash-more[open] .dash-more-hide {
  display: inline;
}

.dash-more-body {
  padding: 0 12px 12px;
}

.dash-more-body p {
  margin: 0 0 8px;
  max-width: 90ch;
}

.dash-more-body p:last-child,
.dash-more-body ul:last-child {
  margin-bottom: 0;
}

/* Inside a section row, the note sits under the label at a note's size
   (it was the one 12px note) and takes the row's width. */
.dash-section-body > .dash-more {
  margin: 8px 0 0;
}

/* In the controls column the line wraps instead: that column is 380px,
   and a stand-down note's line cut to "Not shown: nothing…" was the only
   thing saying why a switched-on section does not show. Its height is
   two or three lines there, which the reason is worth. The toggle stays
   at the right of the first line. */
.dash-split-controls .dash-more-line,
.dash-section-body > .dash-more .dash-more-line {
  overflow: visible;
  text-overflow: clip;
  white-space: normal;
}

/* And the line runs round the toggle rather than beside it. As two flex
   items the toggle kept a column of its own the height of the whole
   line, and in a section row (about 250px of note) the line was left a
   word or two a line — "Not shown: the / “About your / shop” text is /
   empty." The toggle floats at the top right (it is first in the
   markup for this) and the line fills the rest of the first line and
   the full width under it. */
.dash-split-controls .dash-more > summary,
.dash-section-body > .dash-more > summary {
  display: block;
  line-height: 1.45;
}

.dash-split-controls .dash-more > summary > .dash-more-toggle,
.dash-section-body > .dash-more > summary > .dash-more-toggle {
  float: right;
  margin: 0 0 2px 12px;
}

.dash-split-controls .dash-more > summary::after,
.dash-section-body > .dash-more > summary::after {
  content: "";
  display: block;
  clear: both;
}

/* In the bar the note is inside the bar already: no frame of its own,
   and no margin under the line. */
.dash-bar .dash-more {
  margin: 0;
  border: 0;
  background: transparent;
  font-size: var(--d-text-note);
}

.dash-bar .dash-more > summary {
  justify-content: flex-start;
  padding: 0;
}

.dash-bar .dash-more-body {
  padding: 0;
}

.dash-bar .dash-more-line {
  flex: 0 1 auto;
  color: var(--d-ink);
  font-weight: 700;
}

/* ---------- Settings: how the search title and description read ----------
 * partials/seo_result, under the two fields: the words a search result and
 * a shared link will show, since the preview frame cannot show a title.
 * Drawn again by each autosave. */
.dash-seo-result {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--d-line);
}

.dash-seo-result h4 {
  margin: 0 0 4px;
  font-size: var(--d-text-body);
}

.dash-seo-lines {
  margin: 8px 0 0;
}

.dash-seo-lines dt {
  margin-top: 10px;
  font-size: var(--d-text-note);
  color: var(--d-muted);
}

.dash-seo-lines dd {
  display: grid;
  gap: 2px;
  margin: 2px 0 0;
  overflow-wrap: anywhere;
}

.dash-seo-lines dd strong {
  font-weight: 600;
}

/* The picture a shared link shows, small: it is the answer, not the control. */
.dash-seo-picture {
  display: block;
  max-width: 200px;
  max-height: 120px;
  border-radius: 6px;
  -o-object-fit: contain;
     object-fit: contain;
}

/* ---------- Promotions ----------
 * The `commercial` tab: a panel per page a block shows on (the category
 * pages a part of the Home page panel), each with its own list. One
 * column, at a reading width rather than the page's: every block is a
 * card and its fields, and neither gets better wider. Nothing here is a
 * .dash-grid — its 240px minimum in a row pushed a 375px screen 2px
 * sideways when this page used it. */
.dash-promo-page {
  max-width: 760px;
}

/* An author rule that sets `display` beats the UA's `[hidden]`; on this
   page the script hides and shows buttons, bars and notes by attribute. */
.dash-promo-page [hidden] {
  display: none;
}

.dash-promo-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 4px 12px;
  margin: 0 0 4px;
}

.dash-promo-head h2 {
  margin: 0;
  font-size: var(--d-text-heading);
  line-height: 1.3;
}

.dash-promo-head h3 {
  margin: 0;
  font-size: var(--d-text-body);
  line-height: 1.4;
}

/* Category pages: a part of the Home page panel, under its own rule. */
.dash-promo-count {
  color: var(--d-muted);
  font-size: var(--d-text-note);
  white-space: nowrap;
}

.dash-promo-panel > .dash-note {
  margin: 0 0 12px;
}

/* A fact about the page, not a warning: plain, on a quiet ground. */
.dash-note.dash-promo-info {
  padding: 8px 12px;
  border: 1px solid var(--d-line);
  border-radius: 6px;
  background: #f6f7f9;
}

.dash-promo-empty {
  margin: 4px 0 0;
  padding: 12px 16px;
  border: 1px dashed #cfd4db;
  border-radius: var(--d-radius);
  background: #fafbfc;
  color: var(--d-muted);
  font-size: var(--d-text-note);
}

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

.dash-promo-add {
  margin-top: 12px;
}

.dash-promo-fallback > summary {
  list-style: none;
}

.dash-promo-fallback > summary::-webkit-details-marker {
  display: none;
}

/* One block: the arrows, the card, the switch; the fields under the card.
   The arrows are the section rows' own (.dash-section-move). */
.dash-promo {
  display: grid;
  /* No arrows since round 9's item 7: a block is moved in its page's
     own order list, which the card links to (.dash-promo-place). */
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "card show" "edit edit";
  gap: 8px 12px;
  align-items: start;
  padding: 12px 0;
  border-top: 1px solid var(--d-line);
}

.dash-promo:first-child {
  border-top: 0;
}

/* A saved block's way to its row in its page's order list. */
.dash-promo-place {
  align-self: flex-start;
  margin-top: 4px;
  font-size: var(--d-text-meta);
}

/* The card: a miniature of the block as the shop draws it — a 16:9
   picture, the title, two lines of the text, where it leads — in the
   dashboard's own colours. */
.dash-promo-card {
  grid-area: card;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  min-width: 0;
}

/* A picture icon on a neutral ground stands in for no picture, and for
   one that does not load (the script hides the <img>). */
.dash-promo-thumb {
  position: relative;
  flex: 0 0 112px;
  width: 112px;
  height: 63px;
  overflow: hidden;
  border-radius: 6px;
  background: #eef1f5 url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%239aa1ad' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='5' width='18' height='14' rx='2'/%3E%3Ccircle cx='9' cy='10' r='1.6'/%3E%3Cpath d='M21 16l-5-5-8 8'/%3E%3C/svg%3E") center/26px no-repeat;
}

.dash-promo-thumb img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  -o-object-fit: cover;
     object-fit: cover;
}

.dash-promo-words {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.dash-promo-title {
  font-size: var(--d-text-body);
  font-weight: 600;
  line-height: 1.3;
  overflow-wrap: anywhere;
}

/* No title yet: said, quieter, so it does not read as one. */
.dash-promo-title.dash-promo-none {
  color: var(--d-muted);
  font-weight: 400;
  font-style: italic;
}

.dash-promo-text {
  display: -webkit-box;
  overflow: hidden;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  color: var(--d-muted);
  font-size: var(--d-text-note);
  line-height: 1.45;
  overflow-wrap: anywhere;
}

.dash-promo-link {
  overflow: hidden;
  color: var(--d-muted);
  font-size: var(--d-text-meta);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dash-promo-chip,
.dash-promo-warn {
  align-self: flex-start;
  max-width: 100%;
  margin-top: 4px;
  font-size: var(--d-text-meta);
}

.dash-promo-chip {
  overflow: hidden;
  padding: 1px 8px;
  border-radius: 999px;
  background: #eef1f5;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dash-promo-warn {
  padding: 2px 8px;
  border: 1px solid var(--d-warn-line);
  border-radius: 6px;
  background: var(--d-warn-bg);
  color: var(--d-warn-ink);
}

/* Who a block applies to (round 9, item 8): the radios of a
   .dash-option, and under the one picked, its choices — the category tick
   boxes under "Chosen categories", the chosen sellers and "Find a seller"
   under "One seller" and "A group of sellers". :has() keeps it working
   without the page's script. */
.dash-promo-target {
  margin-top: 16px;
}

.dash-promo-picks {
  display: none;
  gap: 4px;
  margin: 2px 0 0 21px;
}

.dash-promo-target:has([data-mode][value=some]:checked) [data-picks~=some],
.dash-promo-target:has([data-mode][value=one]:checked) [data-picks~=one],
.dash-promo-target:has([data-mode][value=group]:checked) [data-picks~=group] {
  display: grid;
}

/* The category list scrolls in its own box past a dozen or so rows. */
.dash-promo-picks[data-picks=some] {
  max-height: 260px;
  overflow-y: auto;
  padding: 6px 8px;
  border: 1px solid var(--d-line);
  border-radius: 6px;
}

.dash-promo-chosen {
  display: grid;
  gap: 4px;
}

.dash-promo-chosen:empty {
  display: none;
}

.dash-promo-find .dash-field-inline:first-child {
  margin-top: 4px;
}

.dash-promo-found {
  display: grid;
  gap: 2px;
  margin: 4px 0 0;
  padding: 0;
  list-style: none;
}

.dash-promo-found:empty {
  display: none;
}

.dash-promo-found-one {
  width: 100%;
  padding: 6px 8px;
  border: 1px solid var(--d-line);
  border-radius: 6px;
  background: var(--d-panel);
  color: inherit;
  font: inherit;
  font-size: var(--d-text-note);
  text-align: left;
  cursor: pointer;
}

.dash-promo-found-one:hover,
.dash-promo-found-one:focus-visible {
  border-color: var(--d-accent);
  outline: none;
}

/* Switched off: greyed, so the list reads the way the shop will. */
.dash-promo-off .dash-promo-card {
  opacity: 0.45;
}

.dash-promo-switch {
  grid-area: show;
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--d-muted);
  font-size: var(--d-text-note);
  cursor: pointer;
}

.dash-promo-switch .dash-switch {
  flex: 0 0 auto;
  margin-top: 0;
}

.dash-promo-edit {
  grid-area: edit;
  min-width: 0;
}

.dash-promo-edit > summary {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 4px 0;
  color: var(--d-accent);
  font-size: var(--d-text-note);
  font-weight: 600;
  list-style: none;
  cursor: pointer;
}

.dash-promo-edit > summary::-webkit-details-marker {
  display: none;
}

.dash-promo-edit > summary::before {
  content: "";
  width: 6px;
  height: 6px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(-45deg);
  transition: transform 0.15s;
}

.dash-promo-edit[open] > summary::before {
  transform: rotate(45deg);
}

.dash-promo-edit > summary:focus-visible {
  outline: 2px solid var(--d-accent);
  outline-offset: 2px;
  border-radius: 4px;
}

.dash-promo-fields {
  margin-top: 4px;
  padding: 4px 0 8px 16px;
  border-left: 2px solid var(--d-line);
}

.dash-promo-fields .dash-field-inline:first-child {
  margin-top: 8px;
}

/* A field's note under its name is a note on every page now
   (.dash-field > .dash-note), not only here. */
.dash-promo-delete {
  margin-top: 16px;
}

/* Deleted until the page is saved: one line, and the way back. */
.dash-promo-gone-on > .dash-promo-card,
.dash-promo-gone-on > .dash-promo-switch,
.dash-promo-gone-on > .dash-promo-edit {
  display: none;
}

.dash-promo-gone {
  grid-column: 1/-1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 8px;
  min-width: 0;
  padding: 8px 12px;
  border-radius: 6px;
  background: #f6f7f9;
  color: var(--d-muted);
  font-size: var(--d-text-note);
}

.dash-promo-gone-title {
  max-width: 100%;
  overflow: hidden;
  color: var(--d-ink);
  font-weight: 600;
  text-decoration: line-through;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.dash-promo-undo {
  padding: 0;
  border: 0;
  background: none;
  color: var(--d-accent);
  font: inherit;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}

/* The site's raw markup, as a part of the Home page panel. */
.dash-raw-inset {
  margin: 24px 0 0;
  padding: var(--d-pad);
  border: 1px solid var(--d-line);
  border-radius: var(--d-radius);
  background: #fafbfc;
}

.dash-raw-inset > h3 {
  margin: 0 0 4px;
  font-size: var(--d-text-body);
}

/* One Save for a long page, in reach wherever the form is: it sticks to
   the foot of the window and settles under the last panel. */
.dash-promo-bar {
  position: sticky;
  bottom: 0;
  z-index: 5;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 16px;
  padding: 12px 16px;
  border: 1px solid var(--d-line);
  border-radius: var(--d-radius);
  background: var(--d-panel);
  box-shadow: 0 -6px 16px rgba(16, 24, 32, 0.06);
}

/* Ads (round 9, item 9): the platform's, read-only, after a page's own
   blocks. The same card as a block, with no arrows, switch or fields, and
   a label saying whose it is. */
.dash-promo-ads {
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px dashed var(--d-line);
}

.dash-promo-ads-head {
  margin: 0 0 4px;
  font-size: var(--d-text-body);
  line-height: 1.4;
}

.dash-promo-ads > .dash-note {
  margin: 0 0 8px;
}

.dash-promo-ad {
  padding: 12px 0;
  border-top: 1px solid var(--d-line);
}

.dash-promo-ad:first-child {
  border-top: 0;
}

.dash-promo-ad-label {
  align-self: flex-start;
  padding: 1px 8px;
  border-radius: 6px;
  background: #eef1f5;
  color: var(--d-muted);
  font-size: var(--d-text-meta);
}

.dash-promo-ad-where,
.dash-promo-ad-status {
  font-size: var(--d-text-note);
  line-height: 1.45;
}

.dash-promo-ad-status {
  color: var(--d-muted);
}

/* Not showing where it is listed right now (switched off, not started,
   ended, its page's products off, or a place the pages lack): greyed,
   as a switched-off block is. */
.dash-promo-ad-quiet .dash-promo-thumb,
.dash-promo-ad-quiet .dash-promo-title,
.dash-promo-ad-quiet .dash-promo-text {
  opacity: 0.55;
}

/* A phone: the card and the switch on the first line, Edit on the second,
   so the card and the open fields have the whole width (the desktop's
   grid since round 9's item 7 took the arrows away). */
@media (max-width: 560px) {
  .dash-promo {
    gap: 8px 12px;
  }
  .dash-promo-thumb {
    flex-basis: 80px;
    width: 80px;
    height: 45px;
  }
  .dash-promo-card {
    gap: 8px;
  }
  .dash-promo-switch {
    flex-direction: column;
    gap: 4px;
  }
  .dash-promo-fields {
    padding-left: 12px;
  }
  /* "No link: shown as a notice" is a sentence; cut at 150px it was not. */
  .dash-promo-link {
    white-space: normal;
    overflow-wrap: anywhere;
  }
}
/* ---------- polish: page helpers ----------
 * Small rules the page polishers need for their own views, each under a
 * comment naming who added it. Everything above this block is the type
 * and spacing scale (the "type" polisher's); nothing here restyles it. */
/* design polisher — the signed-out card (auth/login, auth/forgot): the
   "Stay signed in" box and the link under the form, which had their
   spacing inline. The box is a .dash-check like every other option; it
   keeps a field's gap below it before the button. */
.dash-card-check {
  margin: 0 0 12px;
}

.dash-card-foot {
  margin: 16px 0 0;
}

/* manage polisher — the manage pages and Settings, in place of the
   inline styles they carried (collection_edit, seller_edit, settings,
   reviews), and the Shops row. */
/* A box that is a field of its own in a .dash-grid (a collection's "Show
   it on your shop"): the height of the controls beside it and level with
   their foot, rather than a margin guessed to line it up. */
.dash-check-field {
  align-self: end;
  align-items: center;
  min-height: var(--d-control-h);
  margin: 0 0 12px;
  font-size: var(--d-text-body);
}

.dash-check-field input {
  margin: 0;
}

/* The picture that is there now (a seller's banner, the share picture),
   and the box that removes it, above the fields that replace it. */
.dash-picture-now {
  display: block;
  width: 100%;
  max-width: 420px;
  margin: 4px 0 8px;
  border-radius: 6px;
}

/* Hidden until there is a picture (Settings: shown by the page's script
   after an upload). `display: block` above would beat the attribute. */
.dash-picture-now[hidden],
.dash-check[hidden] {
  display: none;
}

/* A picture refused at the upload, beside its field. */
.dash-upload-error {
  color: var(--d-danger);
}

.dash-check-gap {
  margin: 0 0 12px;
}

/* One of a picture's two fields — the upload, or the address — inside
   the field that names the picture: a label of its own, lighter than the
   field's name above it. */
.dash-subfield {
  display: block;
  margin: 12px 0 0;
}

.dash-subfield:first-of-type {
  margin-top: 4px;
}

.dash-subfield > span {
  display: block;
  margin-bottom: 4px;
  font-size: var(--d-text-note);
}

/* A picture upload: the browser's file field under a button of our own
   and the chosen file's name, so the words are the dashboard's ("Choose
   a picture", "No picture chosen") in the dashboard's language rather
   than the browser's "Choose File". The field covers the button and the
   name, transparent, so a click anywhere on them is a click on it; it
   keeps the focus, and the button shows it. */
.dash-subfield > .dash-file,
.dash-file {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 12px;
  margin: 0;
  font-size: var(--d-text-body);
  font-weight: 400;
}

.dash-file input[type=file] {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.dash-file input[type=file]:focus-visible + .dash-btn-o {
  outline: 2px solid var(--d-accent);
  outline-offset: 2px;
}

.dash-file-name {
  min-width: 0;
  color: var(--d-muted);
  font-size: var(--d-text-note);
  overflow-wrap: anywhere;
}

/* A picker that would otherwise run the width of its panel. */
.dash-field-limit {
  max-width: 520px;
}

/* A form of its own under the one above it (Delete this collection). */
.dash-form-after {
  margin-top: var(--d-gap);
}

/* A hidden review's row, greyed as the storefront drops it. */
.dash-table tr.dash-review-off {
  opacity: 0.55;
}

.dash-pager {
  margin-top: 12px;
}

/* A shop on the Shops page: the arrows, the name with its counts, and the
   two boxes. The plain section row has three columns (arrows, switch,
   body), so the name was squeezed into the switch's 44px and the boxes
   wrapped a word to a line. */
.dash-shop-row {
  grid-template-columns: 32px minmax(0, 1fr) auto auto;
}

.dash-shop-row > .dash-check {
  padding-top: 2px;
}

@media (max-width: 560px) {
  .dash-shop-row {
    grid-template-columns: 32px minmax(0, 1fr);
    row-gap: 6px;
  }
  .dash-shop-row > .dash-check {
    grid-column: 2;
  }
}
/* design polisher — Compare's page switcher on a phone: three segments at
   the body size are wider than a 375px screen's card and the third was
   cut off. The whole width, shared, at the note size. */
@media (max-width: 560px) {
  .dash-compare-pages {
    width: 100%;
  }
  .dash-compare-pages .dash-seg {
    flex: 1 1 auto;
  }
  .dash-compare-pages .dash-seg span {
    padding: 8px 10px;
    font-size: var(--d-text-note);
    text-align: center;
  }
}
/* ---------- a category's tile photo (Categories, round 9 item 5) ---------- */
/* Under the category's name: the picture the tile draws, what it is, and
   Change. Wraps under the name on a phone, where the row's name column is
   about 200px. */
.dash-cat-photo {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 8px;
  margin-top: 8px;
}

.dash-cat-photo-thumb {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  overflow: hidden;
  border: 1px solid var(--d-line);
  border-radius: 6px;
  background: var(--d-bg);
}

.dash-cat-photo-thumb img {
  display: block;
  width: 100%;
  height: 100%;
  -o-object-fit: cover;
     object-fit: cover;
}

.dash-cat-photo-what {
  display: flex;
  flex: 1 1 140px;
  flex-direction: column;
  min-width: 0;
}

.dash-cat-photo-label {
  color: var(--d-muted);
  font-size: var(--d-text-note);
  overflow-wrap: anywhere;
}

.dash-cat-photo-gone {
  color: var(--d-warn-ink);
  font-size: var(--d-text-meta);
}

.dash-cat-photo-gone[hidden],
.dash-cat-photo .dash-btn-o[hidden] {
  display: none;
}

/* ---------- the top banner's photos and buttons (Home page, round 9 item 4;
   partials/hero_banner) ---------- */
/* Author display rules (.dash-option's grid, .dash-field's block) beat the
   hidden attribute's own display: none, and the script shows and hides
   these parts with it. */
.dash-hero[hidden],
.dash-hero [hidden] {
  display: none;
}

.dash-hero-list {
  display: grid;
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.dash-hero-list .dash-cat-photo {
  margin-top: 0;
}

.dash-hero-slots {
  display: grid;
  gap: 8px;
  justify-items: start;
}

.dash-hero-buttons {
  display: grid;
  gap: 12px;
}

.dash-hero-button {
  min-width: 0;
  margin: 0;
  padding: 10px 12px 2px;
  border: 1px solid var(--d-line);
  border-radius: 8px;
}

.dash-hero-button legend {
  padding: 0 4px;
}

.dash-hero-button .dash-field {
  margin: 0 0 10px;
}

.dash-hero-button input,
.dash-hero-button select {
  width: 100%;
  max-width: 100%;
}

.dash-hero-problem {
  margin: 0 0 10px;
  color: var(--d-warn-ink);
}

/* ---------- the photo picker (partials/photo_picker) ---------- */
/* A modal: its own layer above the split page, 16px from every edge on a
   phone, scrolling inside itself. */
.dash-picker {
  width: min(760px, 100vw - 32px);
  max-height: calc(100vh - 32px);
  padding: var(--d-pad);
  overflow: auto;
  border: 1px solid var(--d-line);
  border-radius: var(--d-radius);
  background: var(--d-panel);
  color: var(--d-ink);
}

.dash-picker::backdrop {
  background: rgba(22, 24, 29, 0.45);
}

.dash-picker-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
}

.dash-picker-head h2 {
  margin: 0;
  font-size: var(--d-text-heading);
  overflow-wrap: anywhere;
}

.dash-picker-close {
  flex: 0 0 auto;
  width: var(--d-control-h-small);
  height: var(--d-control-h-small);
  padding: 0;
  border: 1px solid var(--d-line);
  border-radius: 6px;
  background: none;
  color: var(--d-ink);
  font: inherit;
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
}

.dash-picker-own {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 12px 0 4px;
}

.dash-picker [aria-pressed=true].dash-btn-o {
  background: var(--d-accent);
  color: var(--d-accent-ink);
}

.dash-picker-sub {
  margin: 16px 0 8px;
  font-size: var(--d-text-body);
}

.dash-picker-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(112px, 1fr));
  gap: 12px;
  margin: 0 0 12px;
  padding: 0;
  list-style: none;
}

.dash-picker-item {
  display: flex;
  flex-direction: column;
  gap: 4px;
  width: 100%;
  padding: 4px;
  border: 1px solid var(--d-line);
  border-radius: var(--d-radius);
  background: var(--d-panel);
  color: var(--d-ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.dash-picker-item:hover {
  border-color: var(--d-accent);
}

.dash-picker-item[aria-pressed=true] {
  border-color: var(--d-accent);
  box-shadow: 0 0 0 2px var(--d-accent);
}

.dash-picker-item img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1/1;
  -o-object-fit: cover;
     object-fit: cover;
  border-radius: 6px;
  background: var(--d-bg);
}

.dash-picker-name {
  display: -webkit-box;
  overflow: hidden;
  font-size: var(--d-text-note);
  line-height: 1.35;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow-wrap: anywhere;
}

.dash-picker-shop {
  color: var(--d-muted);
  font-size: var(--d-text-meta);
}

.dash-picker-note {
  margin-top: 12px;
}

/* ---------- the store environment ----------
 *
 * The top bar on every signed-in page (partials/topbar, App\Dashboard\TopBar)
 * and, below it, the pages that are not Layout's: Home, Earnings and
 * Concepts (dashboard/env_layout). From the approved mockup
 * (docs/design/store-environment/): Figtree for the interface, Instrument
 * Serif for headings, the mockup's neutrals, and the department's shades
 * (App\Dashboard\Brand, on <body> as --env-deep and the rest) wherever the
 * brand shows. Layout's own pages keep their look under the bar.
 *
 * Both fonts are self-hosted, from @fontsource (OFL): EU-first, and nothing
 * about a store's visit leaves this origin. A face is downloaded only when a
 * page uses it, and each comes in two files (latin, latin-ext) so a Finnish
 * or Dutch page fetches one.
 */
@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/vendor/@fontsource/figtree/files/figtree-latin-ext-400-normal.woff2?868ced668fae732a38c456adf58cb081) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/vendor/@fontsource/figtree/files/figtree-latin-400-normal.woff2?28d8df97d9b4bd55e4fceb45fdcbea40) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/fonts/vendor/@fontsource/figtree/files/figtree-latin-ext-500-normal.woff2?107281732a72a81d40a4654254a6a9b8) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(/fonts/vendor/@fontsource/figtree/files/figtree-latin-500-normal.woff2?a60da9074639a942c8861271320027c7) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/fonts/vendor/@fontsource/figtree/files/figtree-latin-ext-600-normal.woff2?f6a4d53bd7c479f3679b9f497e093c2e) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(/fonts/vendor/@fontsource/figtree/files/figtree-latin-600-normal.woff2?fd40ad719d547d67e63231407a5a677e) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/fonts/vendor/@fontsource/figtree/files/figtree-latin-ext-700-normal.woff2?b1e4551b58505e60b640b8c2a5f7439e) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/fonts/vendor/@fontsource/figtree/files/figtree-latin-700-normal.woff2?e59bc5f6400f0d18747b83d09aedef36) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Instrument Serif";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/vendor/@fontsource/instrument-serif/files/instrument-serif-latin-ext-400-normal.woff2?7c8bacc1c9ea6ace421750fcfacaad01) format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Instrument Serif";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/vendor/@fontsource/instrument-serif/files/instrument-serif-latin-400-normal.woff2?3134e59245730678fd734a44bf383c79) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
:root {
  /* The mockup's neutrals: the ground, the surface, three inks and three
     lines. Semantic, not brand: a department recolours none of them. */
  --env-ground: #f6f5f1;
  --env-surface: #ffffff;
  --env-ink: #1c1c1a;
  --env-muted: #5e5d58;
  --env-body: #4a4944;
  --env-hairline: #e4e2db;
  --env-rule: #efede7;
  --env-field: #d6d3ca;
  --env-font: "Figtree", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --env-serif: "Instrument Serif", Georgia, serif;
  /* Kirppari-Kalle's shades (Brand::shades('#4BA84D')), for anything drawn
     before <body> brings the login's own. */
  --env-deep: #2d642e;
  --env-dark: #387d3a;
  --env-vivid: #3c853d;
  --env-sage: #e9f5ea;
  --env-lightg: #eff7ef;
  --env-line: #c9e5ca;
}

/* How much of the window the sticky top bar takes, for everything that
   sticks below it (the sidebar, the bar of unpublished changes, a split
   page's preview, Compare's bar). Set only where the page has the bar, and
   0 on a phone, where the bar scrolls away. */
.dash-has-top {
  --dash-top-h: 64px;
}

html:has(.dash-has-top) {
  scroll-padding-top: 76px;
}

@media (max-width: 700px) {
  .dash-has-top {
    --dash-top-h: 0px;
  }
  html:has(.dash-has-top) {
    scroll-padding-top: 12px;
  }
}
/* The bar: 64px, white, a hairline under it; the brand and the tools share
   the width either side, so the tabs sit in the middle, as in the mockup
   and in Drive's copy of it. */
.dash-top {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 16px;
  height: 64px;
  padding: 0 32px;
  background: var(--env-surface);
  border-bottom: 1px solid var(--env-hairline);
  color: var(--env-ink);
  font-family: var(--env-font);
  line-height: 1.5;
}

.dash-top-brand,
.dash-top-tools {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  align-items: center;
}

.dash-top-brand {
  gap: 12px;
}

.dash-top-mark {
  flex: none;
  width: 34px;
  height: 34px;
  border-radius: 10px;
  background: var(--env-deep);
  color: #ffffff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.02em;
}

.dash-top-names {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.dash-top-wordmark,
.dash-top-sub {
  line-height: 1.1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.dash-top-wordmark {
  font-size: 15px;
  font-weight: 700;
}

.dash-top-sub {
  font-size: 12px;
  font-weight: 500;
  color: var(--env-muted);
}

.dash-top-tabs {
  flex: none;
  display: flex;
  align-items: stretch;
  gap: 4px;
  height: 64px;
}

.dash .dash-top-tab {
  height: 64px;
  padding: 2px 18px 0;
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 15px;
  font-weight: 500;
  color: var(--env-muted);
  text-decoration: none;
  white-space: nowrap;
  border-bottom: 2px solid transparent;
}

.dash .dash-top-tab:hover {
  color: var(--env-ink);
}

.dash .dash-top-tab.on {
  font-weight: 600;
  color: var(--env-ink);
  border-bottom-color: var(--env-deep);
}

.dash .dash-top-tab:focus-visible {
  outline: 2px solid var(--env-deep);
  outline-offset: -6px;
  border-radius: 8px;
}

.dash-top-tools {
  justify-content: flex-end;
  gap: 10px;
}

.dash-top-bell {
  position: relative;
  flex: none;
  width: 44px;
  height: 44px;
  border-radius: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--env-ink);
}

.dash-top-bell:hover {
  background: var(--env-ground);
}

.dash-top-bell:focus-visible,
.dash-top-account-button:focus-visible {
  outline: 2px solid var(--env-deep);
  outline-offset: 2px;
}

/* The unread dot: 9px of colour in a 2px white ring, as drawn. */
.dash-top-dot {
  position: absolute;
  top: 7px;
  right: 8px;
  width: 13px;
  height: 13px;
  border-radius: 7px;
  background: #b4481f;
  border: 2px solid #ffffff;
}

.dash-top-account {
  position: relative;
  flex: none;
}

.dash-top-account-button {
  list-style: none;
  height: 44px;
  padding: 0 14px 0 8px;
  display: flex;
  align-items: center;
  gap: 8px;
  border: 1px solid var(--env-hairline);
  border-radius: 22px;
  background: var(--env-surface);
  font-size: 14px;
  font-weight: 600;
  color: var(--env-ink);
  cursor: pointer;
}

.dash-top-account-button::-webkit-details-marker {
  display: none;
}

.dash-top-avatar {
  flex: none;
  width: 28px;
  height: 28px;
  border-radius: 14px;
  background: var(--env-sage);
  color: var(--env-deep);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  font-weight: 700;
}

.dash-top-account-name {
  max-width: 160px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.dash-top-account[open] .dash-top-chevron {
  transform: rotate(180deg);
}

.dash-top-menu {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  z-index: 50;
  width: 260px;
  padding: 8px;
  background: var(--env-surface);
  border: 1px solid var(--env-hairline);
  border-radius: 14px;
  box-shadow: 0 12px 28px rgba(28, 28, 26, 0.12);
}

.dash-top-menu-who {
  margin: 4px 8px 8px;
  font-size: 13px;
  color: var(--env-muted);
  overflow-wrap: anywhere;
}

.dash-top-menu-form {
  margin: 0;
}

.dash .dash-top-menu-item {
  width: 100%;
  min-height: 40px;
  padding: 0 10px;
  border: 0;
  border-radius: 8px;
  background: none;
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  color: var(--env-ink);
  text-align: left;
  cursor: pointer;
}

.dash .dash-top-menu-item:hover {
  background: var(--env-ground);
}

.dash .dash-top-menu-item:focus-visible {
  outline: 2px solid var(--env-deep);
  outline-offset: -2px;
}

/* Narrower: the brand's second line goes first, then its name, keeping
   the mark; then the account's name, keeping its initial. Drive's steps. */
@media (max-width: 1180px) {
  .dash-top {
    padding: 0 20px;
  }
  .dash .dash-top-tab {
    padding: 2px 12px 0;
  }
  .dash-top-sub {
    display: none;
  }
}
@media (max-width: 960px) {
  .dash-top-names,
  .dash-top-account-name {
    display: none;
  }
  .dash-top-brand,
  .dash-top-tools {
    flex: none;
  }
  .dash-top-tabs {
    flex: 1 1 auto;
    justify-content: center;
    min-width: 0;
  }
}
/* A phone: two rows, the mark and the tools, then the tabs, scrolling
   sideways rather than pushing the page wider than the screen. Not sticky:
   the split pages pin their preview at the top of a phone's screen. */
@media (max-width: 700px) {
  .dash-top {
    position: relative;
    height: auto;
    flex-wrap: wrap;
    row-gap: 0;
    padding: 8px 12px 0;
  }
  .dash-top-brand {
    flex: 1 1 auto;
  }
  .dash-top-tabs {
    order: 3;
    flex: 1 0 100%;
    height: 48px;
    justify-content: flex-start;
    overflow-x: auto;
    scrollbar-width: none;
    margin: 0 -12px;
    padding: 0 4px;
  }
  .dash .dash-top-tab {
    height: 48px;
    font-size: 14.5px;
  }
  .dash-top-tools {
    gap: 6px;
  }
}
/* ---------- the store environment's pages: Home, Earnings, Concepts, FAQ ----------
 *
 * dashboard/env_layout: the top bar and a page, no sidebar. The mockup's
 * ground, cards (white, a hairline, 20px corners), serif headings and
 * 15-18px text, the department's shades wherever the brand shows: a
 * button, a link, a tick, an "On". The status pills that are not the
 * brand's — ready to try, coming — keep the mockup's own blue and amber.
 */
.dash-env {
  background: var(--env-ground);
  color: var(--env-ink);
  font-family: var(--env-font);
}

.dash-env a:not([class]) {
  color: var(--env-deep);
  text-underline-offset: 2px;
}

.dash-env a:not([class]):hover {
  color: color-mix(in srgb, var(--env-deep) 78%, #000000);
}

.env-main {
  box-sizing: border-box;
  max-width: 1200px;
  margin: 0 auto;
  padding: 56px 40px 48px;
}

.env-page {
  display: flex;
  flex-direction: column;
  gap: 40px;
}

.env-head {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 760px;
}

.env-kicker,
.env-label {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--env-muted);
}

.env-title {
  margin: 0;
  font-family: var(--env-serif);
  font-size: clamp(38px, 5vw, 60px);
  font-weight: 400;
  line-height: 1.02;
  letter-spacing: -0.01em;
}

.env-lede {
  margin: 0;
  font-size: 18px;
  line-height: 1.5;
  color: var(--env-muted);
}

.env-card {
  background: var(--env-surface);
  border: 1px solid var(--env-hairline);
  border-radius: 20px;
}

.env-home-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr);
  gap: 32px;
  align-items: start;
}

.env-news,
.env-side {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.env-side {
  gap: 24px;
  padding-top: 31px;
}

/* An item's image or video: a 2:1 band, about the mockup's 320px on a
   wide card; a photo fills it, a video is shown whole. */
.env-media {
  display: block;
  width: 100%;
  aspect-ratio: 2/1;
  -o-object-fit: cover;
     object-fit: cover;
  background: var(--env-ink);
}

video.env-media {
  -o-object-fit: contain;
     object-fit: contain;
}

.env-pinned {
  overflow: hidden;
}

.env-pinned-body {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 28px 32px 32px;
}

.env-pinned-kicker {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--env-deep);
}

.env-pinned-title {
  margin: 0;
  font-family: var(--env-serif);
  font-size: 36px;
  font-weight: 400;
  line-height: 1.1;
}

.env-rich {
  font-size: 16px;
  line-height: 1.6;
  color: var(--env-body);
}

.env-rich > :first-child {
  margin-top: 0;
}

.env-rich > :last-child {
  margin-bottom: 0;
}

.env-rich a {
  color: var(--env-deep);
}

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

.env-news-list > li + li {
  border-top: 1px solid var(--env-rule);
}

.env-news-item summary {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  min-height: 44px;
  padding: 18px 28px;
  cursor: pointer;
  list-style: none;
}

.env-news-item summary::-webkit-details-marker {
  display: none;
}

.env-news-item summary:focus-visible {
  outline: 2px solid var(--env-deep);
  outline-offset: -2px;
  border-radius: 20px;
}

.env-news-title {
  font-size: 17px;
  font-weight: 600;
}

.env-news-date {
  flex: none;
  font-size: 14px;
  color: var(--env-muted);
}

.env-news-body {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 0 28px 24px;
}

.env-news-body .env-media {
  border-radius: 12px;
}

.env-empty {
  margin: 0;
  padding: 24px 28px;
  font-size: 16px;
  color: var(--env-muted);
}

.env-list-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 24px 26px;
}

.env-list-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.env-list-head h2,
.env-list-intro h2 {
  margin: 0;
  font-size: 19px;
  font-weight: 600;
}

.env-list-intro {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.env-list-intro p {
  margin: 0;
  font-size: 14px;
  line-height: 1.5;
  color: var(--env-muted);
}

.env-count {
  font-size: 14px;
  color: var(--env-muted);
}

.env-week,
.env-tools {
  margin: 0;
  padding: 0;
  list-style: none;
}

.env-week > li + li,
.env-tools > li + li {
  border-top: 1px solid var(--env-rule);
}

.env-week form {
  margin: 0;
}

.dash .env-check {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 46px;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: 15px;
  color: var(--env-ink);
  text-align: left;
  cursor: pointer;
}

.dash .env-check:focus-visible {
  outline: 2px solid var(--env-deep);
  outline-offset: 2px;
  border-radius: 6px;
}

.env-check-box {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border: 1.5px solid var(--env-field);
  border-radius: 5px;
  background: var(--env-surface);
  color: transparent;
}

.env-check[aria-checked=true] .env-check-box {
  border-color: var(--env-deep);
  background: var(--env-deep);
  color: #ffffff;
}

.env-tools > li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-height: 58px;
  padding: 6px 0;
}

.env-tool-words {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.env-tool-name {
  font-size: 15px;
  font-weight: 600;
}

.env-tool-about {
  font-size: 13px;
  color: var(--env-muted);
}

.env-pill {
  flex-shrink: 0;
  padding: 5px 10px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
}

.env-pill-on {
  background: var(--env-sage);
  color: var(--env-deep);
}

.env-pill-ready {
  background: #e6eef8;
  color: #1f4e86;
}

.env-pill-coming {
  background: #f6ecdd;
  color: #7a4b12;
}

/* A concept being tried in some stores: the mockup's blue, as "ready to try". */
.env-pill-testing {
  background: #e6eef8;
  color: #1f4e86;
}

.env-foot {
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  max-width: 1200px;
  min-height: 56px;
  margin: 0 auto;
  padding: 0 40px;
  border-top: 1px solid var(--env-hairline);
  font-size: 13px;
  color: var(--env-muted);
}

.dash-env .env-foot a {
  display: flex;
  align-items: center;
  min-height: 44px;
  font-weight: 600;
}

/* Earnings: the figures and the estimate, two cards side by side. */
.env-two {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 32px;
  align-items: start;
}

.env-form-card,
.env-estimate {
  display: flex;
  flex-direction: column;
  gap: 18px;
  padding: 28px;
}

.env-form-card h2,
.env-estimate h2 {
  margin: 0;
  font-size: 19px;
  font-weight: 600;
}

.env-form {
  display: flex;
  flex-direction: column;
  gap: 22px;
  margin: 0;
}

.env-field {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.env-field label {
  font-size: 14px;
  font-weight: 600;
}

.env-field-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.env-field-row output {
  font-size: 17px;
  font-weight: 600;
}

.dash .env-field input[type=number] {
  height: 48px;
  padding: 0 14px;
  border: 1px solid var(--env-field);
  border-radius: 10px;
  background: var(--env-surface);
  font: inherit;
  font-size: 17px;
  color: var(--env-ink);
}

.dash .env-field input[type=number]:focus-visible {
  outline: 2px solid var(--env-deep);
  outline-offset: 1px;
}

.env-field input[type=range] {
  width: 100%;
  height: 44px;
  margin: 0;
  accent-color: var(--env-deep);
}

.env-hint {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--env-muted);
}

.env-fee-row,
.env-share-row {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  font-size: 15px;
}

.env-fee-row {
  padding-top: 16px;
  border-top: 1px solid var(--env-rule);
}

.env-fee-row span,
.env-share-row span {
  color: var(--env-muted);
}

.env-form-foot {
  display: flex;
  align-items: center;
  gap: 12px;
}

.dash .env-btn[hidden] {
  display: none;
}

.dash .env-btn {
  height: 46px;
  padding: 0 22px;
  border: 0;
  border-radius: 23px;
  background: var(--env-deep);
  color: #ffffff;
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
}

.dash .env-btn:hover {
  background: color-mix(in srgb, var(--env-deep) 82%, #000000);
}

.dash .env-btn:focus-visible {
  outline: 2px solid var(--env-deep);
  outline-offset: 2px;
}

.env-status {
  font-size: 14px;
  color: var(--env-muted);
}

.env-est-rows {
  display: flex;
  flex-direction: column;
  margin: 0;
}

.env-est-rows > div {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 44px;
  font-size: 15px;
}

.env-est-rows > div + div {
  border-top: 1px solid var(--env-rule);
}

.env-est-rows dt {
  color: var(--env-muted);
}

.env-est-rows dd {
  margin: 0;
  font-weight: 600;
}

.env-pool {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 20px 22px;
  border-radius: 14px;
  background: var(--env-lightg);
}

.env-pool span {
  font-size: 14px;
  font-weight: 600;
  color: var(--env-deep);
}

.env-pool strong {
  font-family: var(--env-serif);
  font-size: clamp(44px, 6vw, 64px);
  font-weight: 400;
  line-height: 1;
  color: var(--env-ink);
}

.env-share-row strong {
  font-weight: 600;
}

.env-how {
  margin: 0;
  padding: 16px;
  border: 1px solid var(--env-rule);
  border-radius: 12px;
  font-size: 14px;
  line-height: 1.55;
  color: var(--env-body);
}

.env-how strong {
  color: var(--env-ink);
}

/* Concepts: the heading with the count beside it, then four cards. */
.env-head-split {
  flex-direction: row;
  align-items: flex-end;
  justify-content: space-between;
  gap: 32px;
  max-width: none;
}

.env-head-words {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: 720px;
}

.env-count-pill {
  flex-shrink: 0;
  padding: 9px 16px;
  border-radius: 999px;
  background: var(--env-surface);
  border: 1px solid var(--env-hairline);
  font-size: 14px;
  font-weight: 600;
}

.env-concept-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 24px;
}

.env-concept {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-height: 272px;
  padding: 28px;
  scroll-margin-top: 88px;
}

.env-concept-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.env-concept-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border-radius: 16px;
  background: var(--env-lightg);
  color: var(--env-deep);
}

.env-concept-name {
  margin: 0;
  font-family: var(--env-serif);
  font-size: 32px;
  font-weight: 400;
  line-height: 1.1;
}

.env-concept-about {
  margin: 0;
  font-size: 16px;
  line-height: 1.55;
  color: var(--env-body);
}

.env-concept-form {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0;
}

/* A card's words take the room, so the buttons sit at the foot of every
   card in a row; "Read more" opens under the short text, "Watch" opens the
   video above the buttons. `hidden` wins over the page's display rules. */
.env-concepts [hidden] {
  display: none;
}

.env-concept-words {
  display: flex;
  flex-direction: column;
  flex-grow: 1;
  gap: 14px;
}

.env-concept-more summary {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 44px;
  font-size: 15px;
  font-weight: 600;
  color: var(--env-deep);
  cursor: pointer;
  list-style: none;
}

.env-concept-more summary::-webkit-details-marker {
  display: none;
}

.env-concept-more summary:focus-visible {
  outline: 2px solid var(--env-deep);
  outline-offset: 2px;
  border-radius: 6px;
}

.env-concept-more summary svg {
  transition: transform 0.15s ease;
}

.env-concept-more[open] summary svg {
  transform: rotate(180deg);
}

.env-concept-more .env-rich {
  padding-bottom: 4px;
}

.env-concept-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
}

/* A card's video: its poster frame (made with ffmpeg) in a 16:9 band, cut
   from the top, where mijnTafel's put their headline; a play button, and
   its length and language. Without a poster, the brand's own colour. */
.dash-env .env-concept-poster {
  position: relative;
  display: block;
  aspect-ratio: 16/9;
  overflow: hidden;
  border-radius: 14px;
  background: var(--env-lightg);
  box-shadow: inset 0 0 0 1px var(--env-hairline);
  color: #ffffff;
  text-decoration: none;
}

.env-concept-poster img {
  display: block;
  width: 100%;
  height: 100%;
  -o-object-fit: cover;
     object-fit: cover;
  -o-object-position: center top;
     object-position: center top;
}

.env-concept-poster-none {
  background: linear-gradient(135deg, var(--env-dark), var(--env-deep));
}

.env-play {
  position: absolute;
  top: 50%;
  left: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  margin: -32px 0 0 -32px;
  border-radius: 50%;
  background: rgba(20, 20, 18, 0.72);
  transition: transform 0.15s ease, background-color 0.15s ease;
}

.env-play svg {
  margin-left: 3px;
}

.env-concept-poster:hover .env-play {
  background: var(--env-deep);
  transform: scale(1.06);
}

.dash-env .env-concept-poster:focus-visible {
  outline: 3px solid var(--env-deep);
  outline-offset: 3px;
}

.env-video-meta {
  position: absolute;
  bottom: 10px;
  left: 10px;
  padding: 4px 10px;
  border-radius: 999px;
  background: rgba(20, 20, 18, 0.72);
  font-size: 13px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* The player over the page: the video at its own shape, as large as the
   window allows, on a dark backdrop. The dialog has no padding of its own,
   so a press on it is a press beside the player (the script closes it). */
.env-player {
  max-width: 94vw;
  max-height: 94vh;
  padding: 0;
  border: 0;
  border-radius: 16px;
  background: #141412;
  color: #ffffff;
  overflow: hidden;
}

.env-player::backdrop {
  background: rgba(20, 20, 18, 0.82);
}

.env-player-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 8px 8px 8px 20px;
}

.env-player-title {
  margin: 0;
  font-family: var(--env-font);
  font-size: 16px;
  font-weight: 600;
}

.dash .env-player-close {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: #ffffff;
  cursor: pointer;
}

.dash .env-player-close:hover {
  background: rgba(255, 255, 255, 0.12);
}

.dash .env-player-close:focus-visible {
  outline: 2px solid #ffffff;
  outline-offset: -2px;
}

.env-player-frame video {
  display: block;
  width: auto;
  height: auto;
  max-width: 94vw;
  max-height: calc(94vh - 60px);
  margin: 0 auto;
  background: #000000;
}

.env-player-edge {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  outline: none;
}

.dash .env-interest {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 46px;
  padding: 0 20px;
  border: 1px solid var(--env-field);
  border-radius: 23px;
  background: var(--env-surface);
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  color: var(--env-ink);
  cursor: pointer;
}

.dash .env-interest:focus-visible {
  outline: 2px solid var(--env-deep);
  outline-offset: 2px;
}

.dash .env-interest[aria-pressed=true] {
  border-color: var(--env-deep);
  background: var(--env-deep);
  color: #ffffff;
}

.env-interest-tick,
.env-interest-on,
.env-interest-note {
  display: none;
}

.env-interest[aria-pressed=true] .env-interest-tick,
.env-interest[aria-pressed=true] .env-interest-on {
  display: inline;
}

.env-interest[aria-pressed=true] .env-interest-off {
  display: none;
}

.env-interest[aria-pressed=true] + .env-interest-note {
  display: inline;
  font-size: 14px;
  color: var(--env-muted);
}

/* FAQ: the search and the categories, then each category's questions,
   a card of <details> like the news list, with a chevron that turns.
   The search hides what it does not find with `hidden`, which the page's
   own display rules must not undo. */
.env-faq [hidden] {
  display: none;
}

.env-faq-tools {
  display: flex;
  flex-direction: column;
  gap: 16px;
  max-width: 760px;
}

.env-faq-search {
  display: flex;
  gap: 10px;
  margin: 0;
}

.env-faq-field {
  position: relative;
  display: flex;
  flex: 1;
  align-items: center;
  min-width: 0;
}

.env-faq-field svg {
  position: absolute;
  left: 16px;
  color: var(--env-muted);
  pointer-events: none;
}

.dash .env-faq-field input {
  box-sizing: border-box;
  width: 100%;
  height: 48px;
  padding: 0 16px 0 46px;
  border: 1px solid var(--env-field);
  border-radius: 24px;
  background: var(--env-surface);
  font: inherit;
  font-size: 16px;
  color: var(--env-ink);
}

.dash .env-faq-field input::-moz-placeholder {
  color: var(--env-muted);
}

.dash .env-faq-field input::placeholder {
  color: var(--env-muted);
}

.dash .env-faq-field input:focus-visible {
  outline: 2px solid var(--env-deep);
  outline-offset: 1px;
}

.dash .env-faq-search .env-btn {
  flex: none;
  height: 48px;
  border-radius: 24px;
}

.env-faq-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.dash-env .env-chip {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  padding: 0 16px;
  border: 1px solid var(--env-field);
  border-radius: 20px;
  background: var(--env-surface);
  color: var(--env-ink);
  font-size: 15px;
  font-weight: 600;
  text-decoration: none;
}

.dash-env .env-chip:hover {
  border-color: var(--env-deep);
}

.dash-env .env-chip:focus-visible {
  outline: 2px solid var(--env-deep);
  outline-offset: 2px;
}

.dash-env .env-chip[aria-current=true] {
  border-color: var(--env-deep);
  background: var(--env-deep);
  color: #ffffff;
}

.env-faq-status {
  margin: 0;
}

/* Empty until a search or a category narrows the list: no room taken,
   but still drawn, so the words said into it later are announced. */
.env-faq-status:empty {
  height: 0;
  margin-top: -16px;
  overflow: hidden;
}

.env-faq-groups {
  display: flex;
  flex-direction: column;
  gap: 36px;
}

.env-faq-group {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.env-faq-group-title {
  margin: 0;
  font-family: var(--env-serif);
  font-size: 30px;
  font-weight: 400;
  line-height: 1.1;
}

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

/* A rule between the questions showing, whichever are hidden between them. */
.env-faq-list > li:not([hidden]) ~ li:not([hidden]) {
  border-top: 1px solid var(--env-rule);
}

.env-faq-item summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 44px;
  padding: 18px 28px;
  cursor: pointer;
  list-style: none;
}

.env-faq-item summary::-webkit-details-marker {
  display: none;
}

.env-faq-item summary:focus-visible {
  outline: 2px solid var(--env-deep);
  outline-offset: -2px;
  border-radius: 20px;
}

.env-faq-q {
  font-size: 17px;
  font-weight: 600;
  line-height: 1.4;
}

.env-faq-chevron {
  flex: none;
  color: var(--env-muted);
  transition: transform 0.15s ease;
}

.env-faq-item[open] .env-faq-chevron {
  transform: rotate(180deg);
}

.env-faq-a {
  max-width: 72ch;
  padding: 0 28px 24px;
}

.env-faq-nomatch {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
}

.env-faq-nomatch p {
  margin: 0;
}

.dash-env .env-faq-nomatch a {
  display: flex;
  align-items: center;
  min-height: 44px;
  font-weight: 600;
}

.env-faq-ask {
  margin: 0;
  font-size: 16px;
  color: var(--env-muted);
}

.dash-env .env-faq-ask a {
  font-weight: 600;
}

@media (prefers-reduced-motion: reduce) {
  .env-faq-chevron,
  .env-concept-more summary svg,
  .env-play {
    transition: none;
  }
}
@media (max-width: 960px) {
  .env-home-grid,
  .env-two,
  .env-concept-grid {
    grid-template-columns: minmax(0, 1fr);
  }
  .env-head-split {
    flex-direction: column;
    align-items: flex-start;
    gap: 16px;
  }
  .env-side {
    padding-top: 0;
  }
}
@media (max-width: 700px) {
  .env-main {
    padding: 32px 16px 40px;
  }
  .env-page {
    gap: 28px;
  }
  .env-pinned-body {
    padding: 22px 20px 24px;
  }
  .env-pinned-title {
    font-size: 30px;
  }
  .env-news-item summary {
    padding: 16px 20px;
  }
  .env-news-body {
    padding: 0 20px 20px;
  }
  .env-faq-item summary {
    padding: 16px 20px;
  }
  .env-faq-a {
    padding: 0 20px 20px;
  }
  .env-faq-group-title {
    font-size: 26px;
  }
  .env-list-card,
  .env-form-card,
  .env-estimate,
  .env-concept {
    padding: 20px;
  }
  .env-concept {
    min-height: 0;
  }
  .env-foot {
    flex-direction: column;
    align-items: flex-start;
    gap: 0;
    padding: 12px 16px;
  }
}
