/* The shop on the page.

   Colours come from the theme's own variables rather than being chosen here,
   so a shop looks like the site it is part of and changing the palette changes
   the shop with it. Nothing sets a font. */

.dst-grid{
  display:grid;
  grid-template-columns:repeat(var(--dst-cols,3), minmax(0,1fr));
  /* Column gap on General - Layout - Rows, like every other grid of cards.
     The clamp is what it falls back to while that is left at zero. */
  gap:var(--ds-card-gap, clamp(16px, 2.4vw, 32px));
  margin:0 0 32px;
}

/* Two across on a tablet, one on a phone - whatever the element was set to.
   A five column grid on a 375px screen is five unreadable slivers. */
@media (max-width: 900px){ .dst-grid{ grid-template-columns:repeat(2,minmax(0,1fr)) } }
@media (max-width: 560px){ .dst-grid{ grid-template-columns:1fr } }

.dst-empty{ grid-column:1 / -1; opacity:.7 }

/* Set on the card rather than the link inside it, so a card with a border or
   a fill has the padding within that rather than outside it. */
/* The card itself is dressed on Theme Settings, Elements, Product cards -
   with the rest of what the site draws rather than on a shop screen. Each
   falls back to what a card always looked like, so a site that never opens
   that card sees no change. */
.dst-card{
  padding:var(--ds-pcard-pad,0);
  background:var(--ds-pcard-bg, transparent);
  color:var(--ds-pcard-text, inherit);
  border:var(--ds-pcard-bw,0) solid var(--ds-pcard-line, transparent);
  border-radius:var(--ds-pcard-radius,0);
}

/* The name is a heading and the price is not, so they take two colours. */
.dst-card .dst-card-name{ color:var(--ds-pcard-head, inherit) }

.dst-card-link{ display:block; text-decoration:none; color:inherit }

.dst-card-pic{
  position:relative; display:block; overflow:hidden;
  border-radius:var(--ds-field-radius,2px);
  background:color-mix(in srgb, var(--ds-text,#fff) 6%, transparent);
  aspect-ratio:3 / 4;
}
.dst-card-pic img{
  width:100%; height:100%; object-fit:cover; display:block;
}

/* ---- what a picture does when pointed at ---- */

/* Named on the grid rather than baked into the card, so one shop can have a
   still catalogue and another a moving one without a second stylesheet. */
.dst-grid.hover-zoom-slow .dst-card-pic img,
.dst-grid.hover-zoom-fast .dst-card-pic img{
  transition:transform var(--dst-hover-speed,.6s) cubic-bezier(.2,0,.2,1);
}
.dst-grid.hover-zoom-fast{ --dst-hover-speed:.25s }

.dst-grid.hover-zoom-slow .dst-card-link:hover .dst-card-pic img,
.dst-grid.hover-zoom-fast .dst-card-link:hover .dst-card-pic img{ transform:scale(1.06) }

/* ---- masonry ---- */

/* Columns rather than grid, because a masonry wall is defined by the pictures
   keeping their own heights - which a grid row cannot do. The cards read down
   each column instead of across, which for a catalogue nobody is reading in
   order is the right trade for the layout. */
.dst-grid.is-masonry{
  display:block;
  column-count:var(--dst-cols,3);
  column-gap:clamp(16px, 2.4vw, 32px);
}
.dst-grid.is-masonry .dst-card{
  break-inside:avoid; -webkit-column-break-inside:avoid;
  margin:0 0 clamp(16px, 2.4vw, 32px);
}
/* The picture keeps its own shape here, which is the whole point. */
.dst-grid.is-masonry .dst-card-pic{ aspect-ratio:auto }
.dst-grid.is-masonry .dst-card-pic img{ height:auto }

@media (max-width: 900px){ .dst-grid.is-masonry{ column-count:2 } }
@media (max-width: 560px){ .dst-grid.is-masonry{ column-count:1 } }

/* ---- bento ---- */

/* A wall of unequal boxes rather than a row of identical ones. The pattern
   repeats every six cards, so a catalogue of any length keeps the rhythm and no
   product needs a setting of its own to be the big one. */
.dst-grid.is-bento{
  grid-template-columns:repeat(6, minmax(0,1fr));
  grid-auto-flow:dense;
}
/* Six products fill three rows exactly.
 *
 * The pattern used to be 4, 2, 2, 3, 3, 2 - sixteen columns of card across a
 * grid six wide, so no row ever came out even. Every row ended one or two
 * columns short, and because a grid stretches its items to the tallest in the
 * row, the leftover turned up as bare card behind a product rather than as the
 * next product along.
 *
 * 4+2, 2+4, 3+3. Eighteen across three rows of six, so the wall closes with a
 * product in every space and no card is asked to be taller than it is. */
.dst-grid.is-bento .dst-card{ grid-column:span 2 }
.dst-grid.is-bento .dst-card .dst-card-pic{ aspect-ratio:1 }

.dst-grid.is-bento .dst-card:nth-child(6n+1),
.dst-grid.is-bento .dst-card:nth-child(6n+4){ grid-column:span 4 }
.dst-grid.is-bento .dst-card:nth-child(6n+1) .dst-card-pic,
.dst-grid.is-bento .dst-card:nth-child(6n+4) .dst-card-pic{ aspect-ratio:16 / 10 }

.dst-grid.is-bento .dst-card:nth-child(6n+5),
.dst-grid.is-bento .dst-card:nth-child(6n){ grid-column:span 3 }
.dst-grid.is-bento .dst-card:nth-child(6n+5) .dst-card-pic,
.dst-grid.is-bento .dst-card:nth-child(6n) .dst-card-pic{ aspect-ratio:4 / 3 }

/* Content height. A grid stretches every card in a row to the tallest of
   them, so the small ones carry the difference as bare card under the
   price. Told not to, each card ends where its own words end. */
.dst-grid.is-bento.is-cardh-fit{ align-items:start }

@media (max-width: 900px){
  .dst-grid.is-bento{ grid-template-columns:repeat(2, minmax(0,1fr)) }
  .dst-grid.is-bento .dst-card,
  .dst-grid.is-bento .dst-card:nth-child(6n+1),
  .dst-grid.is-bento .dst-card:nth-child(6n+4),
  .dst-grid.is-bento .dst-card:nth-child(6n+5){ grid-column:span 1 }
}
@media (max-width: 560px){
  .dst-grid.is-bento{ grid-template-columns:1fr }
}

/* ---- the sideways rail ---- */

/* The frame fills the screen while it is pinned, with the row centered in it.
 *
 * The effect pins at the top of the frame and holds it there for as long as the
 * row takes to run - measured, that was 836px of scrolling. A row of product
 * cards is about 450px tall, so a frame only as tall as its contents left half
 * the screen empty underneath for that whole distance, which reads as a hole in
 * the page rather than as an effect. The demo does not show it because its
 * items are tall enough to fill the screen by themselves. */
.ds-fx-hgallery{
  min-height:100svh;
  display:flex; align-items:center;
}

/* The theme's hgallery pins the frame and slides whatever carries data-track,
   so all this has to do is make the row one line as wide as its contents. The
   pinning, the distance and the scrub are the theme's and are not repeated. */
.ds-fx-hgallery .dst-grid.is-rail{
  display:flex; flex-wrap:nowrap;
  width:max-content; max-width:none;
  align-items:start;
  will-change:transform;
}
.ds-fx-hgallery .dst-grid.is-rail{ margin-bottom:0 }

/* Where the first card lines up is in builder.css, written against the track
   rather than against a product wall - the blog element wears the same rail
   and wanted the same three answers. The card width it measures a third of
   is this one. */
.ds-fx-hgallery .dst-grid.is-rail{ --ds-rail-card:clamp(240px, 26vw, 380px) }
.ds-fx-hgallery .dst-grid.is-rail .dst-card{ flex:0 0 clamp(240px, 26vw, 380px) }

/* Nothing sideways on a phone - the row scrolls with a finger instead, which
   is what a thumb expects and costs no pinning. */
@media (max-width: 700px){
  .ds-fx-hgallery{ min-height:0; display:block }
  .ds-fx-hgallery .dst-grid.is-rail{ width:auto; overflow-x:auto;
    margin-bottom:32px;
    scroll-snap-type:x mandatory; -webkit-overflow-scrolling:touch }
  .ds-fx-hgallery .dst-grid.is-rail .dst-card{ scroll-snap-align:start }
}

/* ---- the stack ---- */

/* The theme's cardstack pins each card in turn and shrinks it back as the next
   arrives over it, so a card has to be tall enough to be worth pinning and the
   wall has to be one column for them to stack rather than sit side by side. */
.ds-fx-cardstack .dst-grid.is-stack{
  grid-template-columns:1fr;
  gap:clamp(16px, 2.4vw, 32px);
}
/* A card on the stack is still a product card.
 *
 * These two were written as the page's own background and the field radius,
 * which meant Theme Settings, Elements, Product cards set a background and a
 * corner and the stack threw both away - there was nowhere at all to say what
 * a stacked card looked like.
 *
 * The card's own setting first, and what the stack always drew behind it. A
 * shop that has never opened that card sees exactly what it saw before; one
 * that has, gets what it asked for.
 *
 * Opaque either way: a stacked card is pinned over the card behind it, so
 * anything see-through shows the previous product through the current one. */
.ds-fx-cardstack .dst-card{
  will-change:transform;
  background:var(--ds-pcard-bg, var(--ds-bg,#0b0b0c));
  border-radius:var(--ds-pcard-radius, var(--ds-field-radius,2px));
}
.ds-fx-cardstack .dst-card-pic{ aspect-ratio:16 / 9 }

/* ---- leaning into the scroll ---- */

/* On the picture's own box, so the hover zoom on the image inside it still has
   a transform of its own to use. */
.dst-grid.has-skew .dst-card-pic{
  transform:skewY(var(--dst-skew,0deg));
  transform-origin:center;
  will-change:transform;
}

@media (prefers-reduced-motion: reduce){
  .dst-grid.has-skew .dst-card-pic{ transform:none }
}

/* ---- how a card arrives ---- */

/* Held back only while the browser can put it back, so a card is never left
   invisible if the script does not run. The class goes on from JavaScript. */
.dst-grid.is-armed .dst-card{
  opacity:0;
  transition:opacity .6s ease, transform .6s cubic-bezier(.2,0,.2,1), filter .6s ease;
  transition-delay:var(--dst-in-delay, 0ms);
}
.dst-grid.is-armed.intro-rise .dst-card{ transform:translateY(24px) }
.dst-grid.is-armed.intro-zoom .dst-card{ transform:scale(.92) }
.dst-grid.is-armed.intro-blur .dst-card{ filter:blur(10px) }

.dst-grid.is-armed .dst-card.is-in{
  opacity:1; transform:none; filter:none;
}

@media (prefers-reduced-motion: reduce){
  .dst-grid.is-armed .dst-card{ opacity:1; transform:none; filter:none; transition:none }
  .dst-grid.hover-zoom-slow .dst-card-link:hover .dst-card-pic img,
  .dst-grid.hover-zoom-fast .dst-card-link:hover .dst-card-pic img{ transform:none }
}

/* Top right, as asked.

   Every part of this is a variable the Badges settings can write, and each
   falls back to what the badge always looked like - so a shop that never opens
   that screen keeps the same badge. */
.dst-badge{
  position:absolute; top:10px; right:10px; z-index:2;
  padding:var(--ds-badge-pad-y,4px) var(--ds-badge-pad-x,10px);
  border-radius:var(--ds-badge-radius,99px);
  border:1px solid var(--ds-badge-border,transparent);
  font-family:var(--ds-badge-font, inherit);
  font-size:var(--ds-badge-size,11px);
  font-weight:var(--ds-badge-weight,400);
  letter-spacing:var(--ds-badge-spacing,.9px);
  text-transform:var(--ds-badge-caps,uppercase);
  line-height:1.2;
  /* The shop's own badge colour first, then the one set with the theme's
     palette, then the accent. Three layers, each one only used when the one
     above it is blank - so the palette dresses every badge on the site and the
     shop can still break from it. */
  background:var(--ds-badge-bg, var(--ds-accent,#fff));
  color:var(--ds-badge-text, var(--ds-bg,#000));
}
.dst-badge.is-out{
  top:auto; bottom:10px;
  border-color:var(--ds-badge-out-border,transparent);
  background:var(--ds-badge-out-bg, color-mix(in srgb, var(--ds-bg,#000) 70%, transparent));
  color:var(--ds-badge-out-text, var(--ds-text,#fff));
}

.dst-card.is-out .dst-card-pic img{ opacity:.55 }

/* The size comes from the level, and nothing else does.
 *
 * The name used to be a span, so it inherited the card's face, case and
 * leading. Written as a heading it picked up all of H3 instead: the display
 * face, uppercase, and a line height of 56px on 70px type - which puts each
 * line inside the one above it, so a product name of more than a word was
 * unreadable. That leading is right for a one line page heading and wrong for
 * anything that wraps.
 *
 * font-size is deliberately not touched here, so Title level still decides it.
 * Everything else is put back to what a card always had. */
.dst-card-name{
  display:block; margin:12px 0 4px;
  /* Everything comes from the level - font, size, case, tracking and leading. */
  color:var(--ds-pcard-head, inherit);
  /* Same reason as the blog card: a product name at a heading size is wider
     than the card, and a word with nowhere to break runs over the edge. */
  overflow-wrap:break-word;
}
.dst-card-price{ display:block; opacity:.85 }
.dst-card-price del{ opacity:.5; margin-right:8px }
.dst-card-price ins{ text-decoration:none }

/* ---- searching ---- */

.dst-search{ position:relative; display:flex; gap:10px; align-items:center;
  flex-wrap:wrap; margin:0 0 24px }
.dst-search input[type=search]{ flex:1 1 220px; min-width:0 }

/* In a sidebar the form has one column to work with.
 *
 * The field asks for 220px and the button for whatever its label needs, which
 * will not sit on one line in a column that narrow - so the row wraps and the
 * button ends up under a full-width field at the width of the word "Search",
 * reading as something left unfinished. Both take the whole column instead. */
.ds-widget .dst-search input[type=search],
.ds-widget .dst-search .ds-btn{ flex:1 1 100% }

/* And it sits closer to what follows it than the same form does on a page. In a
   column the widget below is the next thing read; 24px there reads as a break
   between two unrelated blocks. */
/* The field, not the form.
   The room asked for was under the search box itself, between it and the
   button under it in a column. The form keeps the 24px every copy of it has;
   putting the figure there instead had quietly taken 4px off the sidebar. */
.ds-widget .dst-search input[type=search]{ margin-bottom:10px }

/* A magnifier in the field.
 *
 * The Search button came off, so the box has to say what it is on its own - a
 * field with a placeholder reads as "type something", a field with a magnifier
 * reads as "search".
 *
 * On the input's own background rather than on the form. The form is wider than
 * the field it holds, so an icon positioned against the form sat outside the box
 * to the left of it; a background is measured from the field's own edge and
 * cannot drift. */
.ds-widget .dst-search input[type=search]{
  padding-left:38px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23f3f2f2' stroke-opacity='.55' stroke-width='2.2' stroke-linecap='round'%3E%3Ccircle cx='10.5' cy='10.5' r='6.5'/%3E%3Cpath d='M15.5 15.5 21 21'/%3E%3C/svg%3E");
  background-repeat:no-repeat;
  background-position:14px center;
  background-size:15px 15px;
}

/* What is typed ahead, over the page rather than pushing it down. */
/* Ten pixels inside, and only once.
 *
 * The panel padded itself, then every row padded itself again, so what looked
 * like one inset was two stacked: 6 here and 8 or 10 on whatever sat inside,
 * leaving a message of one line in a box ninety pixels tall. The panel holds
 * the inset and what goes in it sits flush. */
.dst-ahead{
  position:absolute; top:100%; left:0; right:0; z-index:40;
  margin-top:6px; padding:10px;
  background:var(--ds-bg,#0b0b0c);
  border:1px solid var(--ds-line, color-mix(in srgb, var(--ds-text,#fff) 20%, transparent));
  border-radius:var(--ds-field-radius,2px);
  max-height:min(60vh, 420px); overflow:auto;
}
/* A row is padded up and down so the hover band has some height, but not in
   from the sides - the panel already did that. */
.dst-ahead a{
  display:flex; align-items:center; gap:10px;
  /* Room at the sides as well, so the highlight below is a band with the row
     inside it rather than a colour running into the panel's own edges. */
  padding:8px; text-decoration:none; color:inherit; border-radius:2px;
}

/* A suggestion is a row, not a sentence.
 *
 * The theme colours every link on hover - a:hover and .ds-widget a:hover both
 * set --ds-link-hover - so pointing at a product turned its name and its price
 * the accent colour, and a panel of results read as a list of warnings. Written
 * one class deeper than those two so it wins wherever the stylesheets happen to
 * load in.
 *
 * The row says it is under the cursor by lighting up, and the words keep the
 * colour they already had. */
.dst-search .dst-ahead a:hover,
.dst-search .dst-ahead a:focus-visible{
  color:var(--ds-text, inherit);
  background:color-mix(in srgb, var(--ds-text,#fff) 10%, transparent);
}

/* The price stays the quieter of the two, hovered or not. */
.dst-search .dst-ahead a:hover .dst-ahead-price{ color:inherit }
.dst-ahead img{ width:44px; height:44px; object-fit:cover; border-radius:2px; flex:0 0 auto }
.dst-ahead .dst-ahead-name{ flex:1 1 auto; min-width:0 }
.dst-ahead .dst-ahead-price{ flex:0 0 auto; opacity:.75 }
.dst-ahead .dst-ahead-none{ margin:0; padding:0; opacity:.7 }

/* ---- filtering ---- */

.dst-filters-form{ display:flex; flex-wrap:wrap; align-items:flex-end;
  gap:var(--dst-row-gap) var(--dst-col-gap); margin:0 0 20px }
.dst-filter{ display:flex; flex-direction:column; gap:0; flex:1 1 160px; min-width:0 }
.dst-filter-small{ flex:0 1 110px }
/* The opacity is gone. It faded the label into whatever it stood on and no
   setting could reach it - and a colour and a dimming fighting each other is
   two controls for one thing. Elements - Product cards - Filter label sets it
   now; left unset it is the page's own text colour. */
.dst-filter > span{ font-size:12px; margin-bottom:var(--dst-label-gap);
  color:var(--ds-pcard-filter, inherit) }

/* And it is the only thing spacing them.

   The theme gives any select sitting directly inside a label a top margin of
   the same figure - written for a label that is one line with the field under
   it and no separate word of its own. This filter has both, so the label's
   bottom margin and the field's top margin stacked, and the gap under the
   word came out at twice whatever either of them said. Flex items do not
   collapse their margins, so nothing absorbed it. */
.dst-filter > select,
.dst-filter > input{ margin-top:0 }
.dst-clear-filters{ align-self:center }

/* ---- one product ---- */

.dst-product{
  display:grid;
  grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);
  gap:clamp(20px, 4vw, 56px);
  align-items:start;
}
@media (max-width: 860px){ .dst-product{ grid-template-columns:1fr } }

.dst-gallery{ position:relative; display:grid; gap:10px }
.dst-gallery .dst-shot{ display:block; border-radius:var(--ds-field-radius,2px); overflow:hidden }
.dst-gallery .dst-shot img{ width:100%; height:100%; object-fit:cover; display:block }

/* The main picture, full width above the rest, at whatever shape it was shot.
 *
 * It was held to 4:5 and cropped to fill, which is right for a wall of cards
 * where every tile has to match and wrong for the one picture somebody came to
 * look at - a wide shot of an exhaust lost both ends of it, and a square
 * product photograph had its top and bottom taken off. The thumbnails below
 * stay square: they are an index, and an index reads as a row.
 *
 * object-fit goes back to fill, which with a natural height is no crop at all -
 * contain would letterbox it inside a box it no longer has. */
.dst-gallery .dst-shot.is-first img{
  aspect-ratio:auto;
  height:auto;
  object-fit:fill;

  /* The full width of its column, whatever size the file is.
   *
   * A picture narrower than the column leaves a band of empty page either side
   * of it, which reads as a layout fault rather than as a small photograph. So
   * it fills, and where the file is smaller than the column it is enlarged to
   * fit - the softness that costs is the lesser of the two, and it is only ever
   * the difference between the file and the column.
   *
   * Height stays automatic, so filling the width never changes the shape - the
   * picture is scaled, not stretched. */
  width:100%;
  max-width:100%;
}

/* Every shot on one row underneath, however many there are - they shrink to
   fit rather than wrapping onto a second line. */
.dst-thumbs{
  display:grid;
  grid-template-columns:repeat(var(--dst-thumbs,4), minmax(0,1fr));
  gap:10px;
}
.dst-thumbs .dst-shot img{ aspect-ratio:1 }

.dst-nopic-large{ aspect-ratio:3 / 4; border-radius:var(--ds-field-radius,2px);
  background:color-mix(in srgb, var(--ds-text,#fff) 6%, transparent) }

.dst-product-name{ margin:0 0 8px }
.dst-product-price{ font-size:clamp(20px, 2.4vw, 28px); margin:0 0 16px }
.dst-product-price del{ opacity:.5; margin-right:10px }
.dst-product-price ins{ text-decoration:none }

.dst-stockline{ margin:0 0 20px; font-size:14px; opacity:.8 }
.dst-stockline.is-out{ color:var(--ds-form-error,#ff5c5c); opacity:1 }
.dst-stockline.is-low{ opacity:1 }

.dst-buy{ display:flex; flex-wrap:wrap; align-items:flex-end;
  gap:var(--dst-row-gap) var(--dst-col-gap); margin:0 0 var(--dst-row-gap) }

/* The label carries the whole gap under it, rather than the column carrying a
   gap between its two children. One number to change, and it is the number
   somebody reading the CSS would look for. */
.dst-choice{ display:flex; flex-direction:column; gap:0; flex:1 1 140px; min-width:0 }
/* Size, Color, Quantity. The same label type as every other field on the site,
   set by the Form labels row in Typography rather than by a figure written here
   that no setting could reach. */
.dst-choice > span{
  font-size:var(--ds-label-size,13px);
  font-weight:var(--ds-label-weight,500);
  line-height:var(--ds-label-lh,1.4em);
  letter-spacing:var(--ds-label-track,0em);
  text-transform:var(--ds-label-case,none);
  margin-bottom:var(--dst-label-gap,10px);
}

/* The theme gives a field inside a label a 10px top margin - the rule is
   `label > input:not([type=checkbox]):not([type=radio])`, which weighs exactly
   the same as `.dst-buy .dst-choice > input` and loads after it, so an equal
   fight was decided by order and the gap stayed 20. Naming the label element
   here outweighs it, without an !important that would then have to be beaten by
   the next person. */
.dst-buy label.dst-choice > input,
.dst-buy label.dst-choice > select,
.dst-buy label.dst-choice > textarea{ margin-top:0; margin-bottom:0 }
.dst-qty{ flex:0 1 96px }

/* The button takes the whole line once the choices no longer fit beside it. */
.dst-add{ flex:0 0 auto }
@media (max-width: 480px){
  .dst-choice{ flex:1 1 100% }
  .dst-add{ flex:1 1 100%; width:100% }
}

.dst-sku{ font-size:13px; opacity:.6 }

/* Under the button, in the column beside the pictures - not across the foot of
   the page where it sits below the gallery and gets missed. */
.dst-product-body{ margin-top:clamp(20px, 3vw, 36px) }
/* The room above is the shop's to set, and nought unless it says otherwise.
   This was a clamp reaching 72px, written here, that no screen could reach -
   so a product page carried a gap nobody had asked for and nobody could
   remove. */
.dst-related{ grid-column:1 / -1; margin-top:var(--dst-related-gap, 0px) }
.dst-related h2{ margin:0 0 20px }

/* ---- the customer's account ---- */

.dst-account-nav{ display:flex; flex-wrap:wrap; gap:18px; margin:0 0 28px;
  padding:0 0 12px;
  border-bottom:1px solid var(--ds-line, color-mix(in srgb, var(--ds-text,#fff) 18%, transparent)) }
.dst-account-nav a{ text-decoration:none; color:inherit; opacity:.65 }
.dst-account-nav a.is-here{ opacity:1; font-weight:600 }
.dst-account-nav a:hover{ opacity:1 }
.dst-account-nav .dst-signout{ margin-left:auto }


.dst-myorders{ width:100% }

.dst-addresses{ list-style:none; margin:0 0 28px; padding:0; display:grid;
  grid-template-columns:repeat(auto-fill, minmax(240px, 1fr)); gap:16px }
.dst-addresses li{ padding:16px;
  border:1px solid var(--ds-line, color-mix(in srgb, var(--ds-text,#fff) 18%, transparent));
  border-radius:var(--ds-field-radius,2px) }
.dst-addresses address{ font-style:normal; margin:0 0 10px }
.dst-addresses form{ display:inline }
.dst-default{ display:inline-block; margin-right:10px; font-size:12px; opacity:.6 }

/* Anything that removes is red here too, the same as in the admin. */
/* Every action in a card is a real button.
 *
 * They were a solid button beside two underlined words, which read as one thing
 * to press and two things to ignore - and the underlined ones faded into the
 * page on hover. Same shape, same height, same hit area; the difference between
 * them is color, which is what color is for.
 *
 * Done by setting the variables the theme's own button already reads rather than
 * by overriding its declarations, so radius, padding, speed and the hover
 * transition all stay whatever Theme Settings says. */
/* The shop's two are the theme's two.

   These held their own colours, so a shop's Remove was the one red on the
   site with no control over it anywhere. The fallbacks are exactly what
   they were, so nothing moves until the new cards are used. */
.dst-danger{
  --fill:var(--ds-btn3-fill, var(--ds-form-error,#ff5c5c));
  --edge:var(--ds-btn3-edge, var(--ds-form-error,#ff5c5c));
  --ink:var(--ds-btn3-ink, var(--ds-bg,#000));
  --fill-h:var(--ds-btn3-fill-hover, var(--ds-bg,#000));
  --edge-h:var(--ds-btn3-edge-hover, var(--ds-form-error,#ff5c5c));
  --ink-h:var(--ds-btn3-ink-hover, var(--ds-form-error,#ff5c5c));
}

/* The one beside the main action: the same button, drawn as an outline, so it
   is plainly the lesser of the two without being a different kind of control. */
.dst-second{
  --fill:var(--ds-btn2-fill, transparent);
  --edge:var(--ds-btn2-edge, var(--ds-accent,currentColor));
  --ink:var(--ds-btn2-ink, var(--ds-accent,currentColor));
  --fill-h:var(--ds-btn2-fill-hover, var(--ds-accent,currentColor));
  --edge-h:var(--ds-btn2-edge-hover, var(--ds-accent,currentColor));
  --ink-h:var(--ds-btn2-ink-hover, var(--ds-bg,#000));
}

/* The account forms: label above field, one gap, the same as the buy form. */
/* ---- one spacing system for every form in the shop ----
 *
 * Three different pairs of numbers were in use: a form used 18/20, the buy row
 * on a product used 14/16, and the filter row above a grid used 14/16 again but
 * with its own label spacing. Nothing decided that, it just accumulated - and a
 * checkout that spaces its fields differently from the form beside it reads as
 * two plugins rather than one shop.
 *
 * Set once here and used by all three, so changing the rhythm changes it
 * everywhere and there is no second place for it to drift. */
:root,
.dst-fields,
.dst-buy,
.dst-filters-form{
  /* Between one line of fields and the next, and between two side by side.
     Both follow Forms - Inputs in the theme, so a checkout and a contact form
     on the same site are spaced the same way from one control - these used to
     be figures of their own, and the shop was the one form on the site that
     the setting could not reach. The figures stay as the answer for a shop
     running without the theme. */
  --dst-row-gap:var(--ds-field-gap, 18px);
  --dst-col-gap:var(--ds-form-col-gap, var(--ds-gutter, 20px));
  /* Between a label and the field it names. Follows Forms - Fields - Label
     when that has been set, and is 10px until it is. */
  --dst-label-gap:var(--ds-label-gap, 10px);
  --dst-block-gap:36px; /* under a whole form */
}

/* Fields across a line, with their labels, boxes and hints on shared rows.
 *
 * Each field used to be its own flex column, bottom aligned - so the three
 * columns only agreed about where they ended. A hint that wrapped onto a second
 * line pushed its own box up and left the row looking like three fields dropped
 * from different heights, which is exactly what the password form did.
 *
 * `display:contents` on the field takes the box out of the layout and hands its
 * label, its control and its hint straight to the grid, so every label sits on
 * the label row and every box on the box row whatever is written underneath.
 * The label keeps the field's name for anyone clicking it, because the element
 * is still a <label> - it just no longer draws a box of its own. */
.dst-fields{
  display:grid;
  grid-template-columns:repeat(auto-fill, minmax(220px, 1fr));
  /* Label, control, hint. The rows size themselves, and the gap is applied
     between fields rather than between a label and its own box - that spacing
     is the label's own margin. */
  grid-template-rows:auto auto auto;
  grid-auto-rows:auto;
  /* No row gap.
   *
   * The rows are a label, its box and whatever the box has to say - three
   * parts of one field, not three things needing air between them. A row gap
   * put 18px between a label and the box it names on top of the label's own
   * 10px, which is what left the labels floating. Spacing between one line of
   * fields and the next is the field's own bottom margin. */
  column-gap:var(--dst-col-gap);
  row-gap:0;
  align-items:start;
  margin:0 0 var(--dst-block-gap);
}

/* The field stays a real box in one column, and borrows the parent's rows.
 *
 * display:contents aligned everything but lost the columns: a part goes to the
 * first free cell of its row, so a field with no hint let the next field's hint
 * slide left - the password form put "Needs 8 characters" under Current
 * password. Subgrid keeps each field in its own column while its label, box and
 * hint still sit on the shared rows. */
.dst-fields .dst-field{
  display:grid;
  grid-template-rows:subgrid;
  grid-row:span 3;
  min-width:0;
}

/* One rule for the space under everything in the grid.
 *
 * Every direct child gets the same number, whether it is a field, a checkbox or
 * a paragraph - so a form cannot be spaced one way and the form under it
 * another, which is exactly what happened here: the theme carries
 *
 *   label:has(> input:not([type="checkbox"]):not([type="radio"])){ margin-bottom:0 }
 *
 * which outranks a single class. The password fields wrap their input in a box,
 * so that rule missed them and they kept their spacing; the details fields hold
 * a bare input, so it hit them and the Save button ended up against the field
 * above it. The class is named twice to outrank the theme - the space inside
 * this grid belongs to the grid, not to whatever the markup happens to be. */
.dst-fields > .dst-field.dst-field,
.dst-fields > .dst-check,
.dst-fields > p{ margin-bottom:var(--dst-row-gap) }

/* A button is not another field, and reads as the end of the form rather than
   as the next line of it. The field above already contributes a row gap, so
   one more makes the block gap. */
.dst-fields > button{ margin-top:var(--dst-row-gap); margin-bottom:0 }

/* Each part on its own row of the shared track. */
.dst-fields .dst-field > span:first-child{ grid-row:1 }
.dst-fields .dst-field > input,
.dst-fields .dst-field > select,
.dst-fields .dst-field > textarea,
.dst-fields .dst-field > .dst-pw-box{ grid-row:2; min-width:0 }
.dst-fields .dst-field > .dst-pw-says,
.dst-fields .dst-field > small,
.dst-fields .dst-field > .dst-hint{
  grid-row:3;
  font-size:12px; opacity:.7;
  /* Only when it is saying something. An empty span still occupies its row and
     its margin, which is a band of nothing under every field on the form. */
  margin-top:6px;
}

/* A span with nothing in it costs nothing: no line, no margin, no reserved row.
   Otherwise every field on the form carries a band of empty space under it. */
.dst-fields .dst-field > .dst-pw-says:empty{ margin:0; min-height:0 }

/* A field on its own line still spans, and its parts stack in that column. */
.dst-fields .dst-field.is-wide{ grid-column:1 / -1 }

/* Two sections reading across rather than one long column.
 *
 * Profile and Security are two unrelated forms with a button each, and stacked
 * they read as one form with a button in the middle - the password button
 * looked like it belonged to the email field above it. Side by side, each
 * button is plainly under its own set of fields.
 *
 * One column on a narrow screen: two forms three fields wide do not fit a
 * phone, and the order they fall into is the order they were in. */
.dst-twoup{ display:grid; grid-template-columns:repeat(2, minmax(0,1fr));
  gap:var(--dst-block-gap,36px) var(--dst-col-gap,20px); align-items:start }
@media (max-width:820px){ .dst-twoup{ grid-template-columns:minmax(0,1fr) } }
/* A form that wants one field to a line whatever it is given room for. */
.dst-fields-one{ grid-template-columns:minmax(0,1fr) }

/* Four columns, stated rather than fitted, so the span classes mean something.
   The checkout's address is laid out on four and the account edits the same
   address - auto-fill would have given it a different number of columns at
   every width and the two forms would never have matched. */
.dst-fields-four{ grid-template-columns:repeat(4, minmax(0,1fr)) }
@media (max-width:900px){
  .dst-fields-four{ grid-template-columns:repeat(2, minmax(0,1fr)) }
  .dst-fields-four > .dst-field.is-span-3,
  .dst-fields-four > .dst-field.is-span-4{ grid-column:span 2 }
}

/* The label, and only the label. Written as > span it also caught the span the
   password field wraps its input in - so those boxes carried a label's bottom
   margin and their form sat ten pixels lower than the one above it. */
/* The label reads what the panel set.

   It was a hard coded 12px at 70% of whatever colour it inherited, so the
   size on Forms, Fields, Label did nothing to a shop form and there was no
   colour to set at all. Each falls back to what it was, so nothing moves
   until somebody chooses. */
/* The card boxes are labelled the same way, and are not inside a .dst-fields
   grid to inherit it - their container is its own thing, because each field is
   a frame rather than an input. Named here rather than given the values a
   second time, so the case and the colour cannot drift apart. */
.dst-fields .dst-field > span:first-child,
#dst-pay-element .dst-field > span:first-child{
  font-size:var(--ds-label-size, 12px);
  text-transform:var(--ds-label-case, none);
  color:var(--ds-field-label, inherit);
  /* Held back only while it has no colour of its own. A colour somebody
     chose is the colour, not seven tenths of it - and the variable is only
     set when they have chosen one. */
  opacity:var(--ds-field-label-fade, .7);
  /* Transparent unless the Label card names one, so a label sits on whatever
     is behind it exactly as it always has. */
  background:var(--ds-field-label-bg, transparent);
  margin-bottom:var(--dst-label-gap);
}
.dst-fields label.dst-field > input,
.dst-fields label.dst-field > select,
.dst-fields label.dst-field > textarea{ margin-top:0; margin-bottom:0 }
/* A field that takes the whole line. An email address, an address line, a
   message - anything long enough that half a form is the wrong shape for it. */
.dst-fields .dst-field.is-wide{ grid-column:1 / -1 }

.dst-fields .dst-check{ grid-column:1 / -1 }
.dst-fields > button{ grid-column:1 / -1; justify-self:start }


/* ---- signing in, joining, forgetting ---- */

/* A column the width of a form and no wider. These pages hold six fields at
   most, and a sign in box stretched across a 1400px screen puts the label at one
   end of the desk and the box at the other. Sized in ch so it follows the type
   rather than being a figure that stops being right when the font changes. */
.dst-auth{ max-width:46ch; margin-inline:auto }

/* No overrides on the grid here.
 *
 * These two lines used to set gap:0 and display:block, which killed the row
 * gap, the column gap and the space between a label and its field all at once -
 * so the register form had fields touching side by side and stacked with
 * nothing between them. The rules above already lay a form out correctly; this
 * page needed nothing of its own. */

/* The button ends the form: its own line, away from the last field, and the
   width of its own words rather than the width of the page. */
.dst-auth .dst-fields > .ds-btn{
  grid-column:1 / -1;
  justify-self:start;
  margin-top:8px;
}

/* Where else to go: forgotten the password, or has no account yet. Spread
   across the width so the two do not read as one sentence. */
.dst-auth-else{ display:flex; flex-wrap:wrap; gap:8px 24px;
  justify-content:space-between; margin:18px 0 0 }

/* No underline, like every other piece of chrome on the site - the menu, the
   footer links, the top bar. The theme underlines links inside running text,
   which is what tells them apart from the words around them; a link standing on
   its own under a form is not in a sentence and does not need it. */
.dst-auth-else a{ color:var(--ds-accent,inherit); text-decoration:none }
.dst-auth-else a:hover,
.dst-auth-else a:focus-visible{ color:var(--ds-link-hover,inherit) }

/* Agreeing to the terms. Smaller than the form, because it is the fine print and
   should read as it. */
/* The fine print. Its links stay underlined: they sit inside a sentence, and
   there an underline is the only thing separating a link from the words on
   either side of it. */
.dst-auth-small{ margin:14px 0 0; font-size:.85em; opacity:.75; line-height:1.5 }
.dst-auth-small a{ text-underline-offset:.18em }

/* What the last attempt said. Red only when it went wrong - a green "check your
 * email" printed in the color of a failure is a message that reads as one.
 *
 * At the foot of the window, not the head of the content.
 *
 * The growler lifts these into the corner and removes them, so what is styled
 * here is the fallback: the reply set to In form, or no script having run at
 * all. Printed where it sits in the markup it was a block at the very top of
 * the page - on the account screen that put "That is not your current password"
 * above the tabs, a long way from the field it is about, and pushed the whole
 * page down to say it.
 *
 * Fixed to the bottom instead. It is still first in the source, so a screen
 * reader reaches it before the thing it is about; it is simply drawn where the
 * eye is rather than above a fold the reader has already passed. */
.dst-said{
  position:fixed; left:0; right:0; bottom:0; z-index:60;
  margin:0; padding:14px 18px; border-radius:0;
  text-align:center;
  background:color-mix(in srgb, var(--ds-text,#fff) 8%, transparent);
  backdrop-filter:blur(10px); -webkit-backdrop-filter:blur(10px) }
.dst-said.is-bad{ background:color-mix(in srgb, #e5484d 16%, transparent) }

/* The name over a form inside a tab.
 *
 * Smaller than the page's own heading and set apart from what it names by less
 * than the gap between the two forms, so it reads as belonging to the fields
 * below rather than floating between them. */
/* No size, no weight, no case of its own.
 *
 * It carried all three, which made it a seventh heading style agreeing with
 * none of the six the theme already has - and none of them reachable from the
 * admin. The tag is now whichever heading level the store is set to, so the
 * size is Typography's answer and this only says where it sits. */
.dst-formhead{ margin:0 0 14px }
.dst-formhead + .dst-fields{ margin-top:0 }
.dst-fields + .dst-formhead{ margin-top:var(--dst-block-gap, 36px) }

/* The challenge, given room of its own. Its iframe is a fixed size and would
   otherwise sit against the button above it. */
.dst-guard{ margin:6px 0 4px }


/* Straight to the courier for this parcel. Beside the number rather than on it,
   because the number is what somebody reads out on the phone and a link wrapped
   around it is a link they hit while trying to select it. */
.dst-track{ margin-left:10px; white-space:nowrap; color:var(--ds-accent,inherit) }
.dst-ref-track{ display:flex; flex-wrap:wrap; align-items:baseline; gap:8px }


/* ---- the account's address cards ---- */

/* Two across, one under the other on a phone. Shipping and billing are the same
   shape and read side by side, so they are set out that way rather than as a
   list somebody has to scroll to compare. */
.dst-cards{
  display:grid;
  grid-template-columns:repeat(2, minmax(0,1fr));
  gap:clamp(16px, 2.4vw, 28px);
  align-items:start;
}
@media (max-width: 700px){ .dst-cards{ grid-template-columns:1fr } }

.dst-card-block > h3{ margin:0 0 12px }

/* An address, read as an address. One line per line, not a paragraph of commas
   - somebody checking their own street name should find it where it would be on
   an envelope. */
.dst-card-block address{ font-style:normal; display:grid; gap:2px; line-height:1.5 }

/* What can be done to it, under it, with the destructive one set apart from the
   one somebody means to press. */
/* One row. They wrapped because a button was carrying a sentence - the labels
   are short now, and the row only breaks on a screen genuinely too narrow to
   hold three of them. */
/* Three actions on one line.
 *
 * The card is half the page, and Edit, Set as billing and Remove come to 502px
 * of button against 501px of card at a 12px gap - one pixel over, so Remove
 * dropped to a line of its own. Ten closes it.
 *
 * It still wraps rather than overflowing if a label is ever made longer or the
 * page is narrower, which is the right way round for a row of actions. */
.dst-card-does{ display:flex; flex-wrap:wrap; align-items:center; gap:10px; margin-top:16px }

/* Paragraphs with nothing in them.
 *
 * Every one of these screens is drawn inside post content, and the filter that
 * runs over it turns the whitespace between two block level children into a
 * paragraph. An empty one is invisible and still a grid item: it takes a whole
 * row and brings 14px above and 18px below with it.
 *
 * On the address form that put 66px between the last field and Save address,
 * two thirds of it nothing at all. They are dropped rather than zeroed, so they
 * stop taking a cell as well as stop taking room. */
.dst-fields > p:empty,
.dst-checks > p:empty,
.dst-cards > p:empty,
.dst-card-does > p:empty,
.dst-checkout-left > p:empty,
.dst-checkout-right > p:empty{ display:none }

/* Inside the edit form it is a grid item like every field, so it was penned
   into one 250px column and its two buttons stacked. It is a row of actions,
   not a field: it takes the whole width. */
.dst-fields > .dst-card-does{ grid-column:1 / -1 }
@media (max-width: 480px){ .dst-card-does .ds-btn{ flex:1 1 100% } }
/* A form wrapping one button is a box around a button, not a block.

   Each of these is its own form because each posts a different action, and
   a form is display:block - so as flex items they each took the whole 501px
   of the row and the three actions stacked one per line. Sized to their
   contents they sit in a line, which is what a row of actions is. */
.dst-card-does form,
.dst-account .dst-card-does form{
  margin:0; flex:0 0 auto; width:auto; max-width:100%;
}
.dst-cancel{ opacity:.75 }



/* ---- the checkout ---- */

/* One gap between sections, everywhere.

   Written once here rather than as a figure on each block, so the distance
   between two parts of the checkout is the same distance between any other
   two - and changing it is one line. */
.dst-checkout{ --dst-sec-gap:50px }

.dst-checkout .dst-block{ margin:0 0 var(--dst-sec-gap) }
.dst-checkout .dst-block > h2{ margin:0 0 18px }

/* ---- the checkout, in two halves ---- */

/* Where it goes on one side, everything else on the other. Both halves start
   at the top rather than stretching, so a short right hand column does not
   pull its sections apart to match the address. */
.dst-checkout-form{
  display:grid;
  grid-template-columns:1fr 1fr;
  gap:var(--dst-sec-gap,50px);
  align-items:start;
}

/* Anything in the form that is not a column does not get one.
 *
 * A grid lays out every child it has. The nonce, the referer and the action
 * are three hidden inputs at the top of this form, and wpautop leaves an
 * empty paragraph after them - four cells gone before the first real one, so
 * the address landed in the right hand column and everything else wrapped to
 * the row below it. The two halves were side by side in the markup and
 * nowhere near each other on the page. */
.dst-checkout-form > input[type="hidden"],
.dst-checkout-form > p:empty{ display:none }

/* The billing form, open only when the answer is no.

   Written as a rule that hides it rather than one that shows it, so the
   form is there for anything that does not understand :has() - a second
   address form nobody wanted is a nuisance; one that cannot be opened is a
   customer who cannot pay. */
.dst-bill{ margin-top:26px }
.dst-bill > h3{
  font-size:var(--ds-h4-size, 22px);
  font-weight:var(--ds-h4-weight, 600);
  line-height:1.2;
  margin:0 0 15px;
}
.dst-checkout-left:has(.dst-billsame input:checked) .dst-bill{ display:none }

/* Both questions about the address, on one line under it. */
.dst-checks{ display:flex; flex-wrap:wrap; gap:10px 26px; margin-top:4px }

/* The last section in a column has nothing under it to be kept away from. */
.dst-checkout-left > .dst-block:last-child,
.dst-checkout-right > :last-child{ margin-bottom:0 }

/* Four columns in each half, which is what the widths on the fields count
   in - a name is two of them, a street is four, an apartment number is one. */
.dst-checkout .dst-fields{
  grid-template-columns:repeat(4, minmax(0,1fr));
  /* The ticks under a set of fields belong to those fields, so they sit close
     to them. The shared 36px is the gap between one block and the next, and
     used here it read as the checkbox having nothing to do with the boxes
     above it. */
  margin-bottom:20px;
}
/* How many columns a field takes. Not the checkout's own: the account edits
   the same address with the same fields, and it should read the same way. */
.dst-fields > .dst-field.is-span-2{ grid-column:span 2 }
.dst-fields > .dst-field.is-span-3{ grid-column:span 3 }
.dst-fields > .dst-field.is-span-4{ grid-column:span 4 }

/* Every heading on the checkout is a section name, not a page title - so
   they take H4, which is the size Typography gives that job. */
.dst-checkout .dst-block > h2,
.dst-checkout-side > h2{
  font-size:var(--ds-h4-size, 22px);
  font-weight:var(--ds-h4-weight, 600);
  line-height:1.2;
  margin:0 0 15px;
}

@media (max-width:900px){
  .dst-checkout-form{ grid-template-columns:1fr }
  .dst-checkout .dst-fields{ grid-template-columns:repeat(2, minmax(0,1fr)) }
  .dst-checkout .dst-fields > .dst-field.is-span-3,
  .dst-checkout .dst-fields > .dst-field.is-span-4{ grid-column:span 2 }
}
@media (max-width:560px){
  .dst-checkout .dst-fields{ grid-template-columns:1fr }
  .dst-checkout .dst-fields > .dst-field[class*="is-span-"]{ grid-column:span 1 }
}

/* What is being bought, as a list that reads as one.

   It was an unordered list with its markers taken off by the theme's reset,
   so three product names ran together with nothing saying where one ended.
   A mark pointing at the line is enough. */
.dst-summary{ list-style:none; margin:0 0 18px; padding:0 }
.dst-summary li{
  display:grid;
  grid-template-columns:auto minmax(0,1fr) auto;
  gap:10px; align-items:baseline;
  padding:8px 0;
  border-bottom:1px solid var(--ds-line, color-mix(in srgb, currentColor 12%, transparent));
}
.dst-summary li::before{
  content:"\2192";
  color:var(--ds-accent, currentColor);
  line-height:1;
}
.dst-summary li:last-child{ border-bottom:0 }

/* Room over the button, so it is not sitting on the last total. */
.dst-place{ margin-top:10px }

/* The terms line under it reads at full strength.

   .dst-auth-small drops everything it holds to 75%, which is fair for a hint
   and wrong for the sentence saying what somebody is agreeing to - and the
   links inside it were dimmed with it. */
.dst-checkout .dst-agree,
.dst-checkout .dst-agree a{ opacity:1 }

/* ---- the list of what is in the cart ---- */

/* A table shrinks to its content unless it is told otherwise, and nothing
   told this one - so the lines stopped wherever the longest price happened
   to end and left the rest of the column empty. */
.dst-lines{
  width:100%;
  border-collapse:collapse;
  /* Room under the list, so Update cart is not sitting on the last line. */
  margin:0 0 20px;
}

/* Ten each side, so there is room between two columns and room inside every
   one of them - a padding written only on the right is a gap between cells
   and nothing at all against the words themselves. The outer edges are flush,
   because the table already sits inside the page's own margin. */
.dst-lines th{ text-align:left; font-weight:600; padding:0 10px 12px }
.dst-lines td{ padding:14px 10px; vertical-align:middle }

/* A line under the column names, so they read as headings for what follows
   rather than as a first row of the list.

   On the cells rather than on the row: a tr takes no border under
   border-collapse in every browser, and this table collapses its borders. The
   site's own rule, set once on General, so it matches every other line drawn
   on the page. */
.dst-lines thead th{
  border-bottom:1px solid var(--ds-line, color-mix(in srgb, currentColor 14%, transparent));
}
/* A receipt is three columns, not the cart's five.

   Left to itself the browser gave the name only as much room as its longest
   word and handed the slack to the quantity, so a two word product wrapped
   down the left edge with a hand's width of nothing beside it.

   Said as a full width first column rather than as narrow last two. One
   percent on the short columns is the usual trick and it did not work here:
   the table clamped them to their contents as intended and then handed the
   surplus to the quantity anyway, which measured 857px against the name's 85.
   Asking for the whole width on the name leaves the other two nothing to take
   and they fall back to fitting what is in them. */
.dst-lines-order th:first-child,
.dst-lines-order td:first-child{ width:100% }
.dst-lines-order th:nth-child(2),
.dst-lines-order td:nth-child(2),
.dst-lines-order th:last-child,
.dst-lines-order td:last-child{ white-space:nowrap }

/* The count sits with the money rather than against the name - two
   figures read as a pair when they line up on the same edge. */
.dst-lines-order th:nth-child(2),
.dst-lines-order td:nth-child(2){ text-align:right }

.dst-lines th:first-child,
.dst-lines td:first-child{ padding-left:0 }
.dst-lines th:last-child,
.dst-lines td:last-child{ padding-right:0; text-align:right }

/* The name takes whatever is left. Every other column is as wide as what is
   in it, which is what stops a price column being a third of the table. */
.dst-lines td:nth-child(2){ width:100% }
/* The picture's column is as wide as the picture.

   width:1px is the usual way of saying "as narrow as your content", and it
   works right up until another cell is told to take 100% - then the table
   hands that one everything and reads the 1px literally, which collapsed
   this column to its padding and squeezed the picture out of existence. A
   real width cannot be argued with. */
.dst-lines .dst-line-pic{ width:72px; padding-right:14px }
.dst-lines .dst-line-pic img{
  display:block; width:72px; height:auto;
  /* min-width, and max-width off.

     The theme gives every image max-width:100%, and a percentage measured
     against a cell whose own width is still being worked out counts as
     nothing - so the picture's smallest possible size was zero. The name
     column asks for 100%, the table gave it everything, and it was allowed
     to because this column claimed it could shrink to nought. A real
     minimum is the end of that argument. */
  min-width:72px; max-width:none;
  border-radius:var(--ds-field-radius,4px) }

/* How many, not how long.

   The field takes the site's own input width otherwise, which is a width
   meant for an email address - a box wide enough for forty characters
   holding the number 1. */
.dst-lines input[type=number]{
  width:5.5em; min-width:0; text-align:center;

  /* And the two little arrows the browser draws inside it.
   *
   * Chrome gives them a panel of their own in its own grey, so on a dark field
   * they were a pale rectangle sitting in a black box - the one part of the
   * form ignoring the site completely. color-scheme is what decides which way
   * the browser draws its own furniture, and accent-color tints it: the field's
   * text colour, because they are a control for the figure beside them rather
   * than a thing of their own. */
  color-scheme:light dark;
  accent-color:var(--ds-field-text, currentColor);
}

/* Their panel takes the field's own background rather than the browser's.
   Webkit draws the spinner as an element of its own that inherits nothing. */
.dst-lines input[type=number]::-webkit-inner-spin-button,
.dst-lines input[type=number]::-webkit-outer-spin-button{
  background:transparent;
  color:var(--ds-field-text, currentColor);
  opacity:1;
}

/* ---- the shop's own working mark ---- */

/* A button waiting on the cart says so.

   The theme has a spinner for submit buttons, but it is drawn by the forms
   script - which only loads when replies are set to Growler or when Contact
   Form 7 is installed. A shop cannot wait on a contact form plugin to tell
   somebody their basket is thinking, so this is its own.

   currentColor, so it is the button's own lettering whatever the button is
   set to - nothing here picks a colour. */
.dst-spin{
  display:inline-block; flex:none;
  width:1em; height:1em; margin-left:.6em;
  border:2px solid color-mix(in srgb, currentColor 25%, transparent);
  border-top-color:currentColor;
  border-radius:50%;
  animation:dst-spin 800ms linear infinite;
}

@keyframes dst-spin{ to{ transform:rotate(360deg) } }

/* Held, not hidden - a button that vanishes while it works moves the page
   under the pointer. */
.is-working{ cursor:progress; opacity:.85 }

/* The remove cross is a small square button, so its mark replaces the
   cross rather than sitting beside it. */
.dst-drop.is-working{ color:transparent; position:relative }
.dst-drop.is-working .dst-spin{
  position:absolute; inset:0; margin:auto;
  color:var(--ds-btn-text, #000);
}

@media (prefers-reduced-motion: reduce){
  .dst-spin{ animation-duration:2.4s }
}

/* Update cart, and room under it so the discount field does not hit it. */
.dst-cart-foot{ margin:0 0 50px }

/* ---- the discount code ---- */

/* One line: the box and the button that acts on it. Two block level children
   in a form stack, so Apply sat under the field it belongs to and read as a
   second, unrelated control. */
.dst-coupon{
  display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  margin:0 0 20px;
}
.dst-coupon input[type=text]{ flex:1 1 200px; min-width:0 }
.dst-coupon .ds-btn{ flex:0 0 auto }

/* ---- what an order came to ---- */

/* Two columns, label left and figure right, with a rule between the rows.
 *
 * It was a bare definition list, so the browser drew each figure on its own
 * line indented under its label - a column of prices nobody can add up by eye
 * and nothing lining up with anything. The rule is the site's own, set once on
 * the General tab, so a totals table matches every other line on the site. */
.dst-totals{
  display:grid;
  grid-template-columns:1fr auto;
  gap:0;
  margin:24px 0 0;
  /* As wide as whatever holds it.
   *
   * The 420px cap was right when the totals sat under a full width cart and
   * wrong now they sit in a column of their own - a half width panel with the
   * figures stopping two thirds of the way across reads as a table that failed
   * to finish. Anything narrower than the old cap is unaffected. */
  max-width:none;
}

.dst-totals dt,
.dst-totals dd{
  margin:0;
  padding:10px 0;
  border-top:var(--ds-rule, 1px solid color-mix(in srgb, currentColor 14%, transparent));
}

.dst-totals dt{ color:var(--ds-accent,inherit) }

/* The figures line up on their last digit, which is the only way a column of
   money reads as a column. */
.dst-totals dd{ text-align:right; font-variant-numeric:tabular-nums }

/* The first row has the heading above it, not another row - no rule. */
.dst-totals dt:first-of-type,
.dst-totals dt:first-of-type + dd{ border-top:0 }

/* The total is the answer, so it is set apart from the workings above it. */
.dst-totals .is-total,
.dst-totals .is-total + dd{
  font-weight:600;
  border-top-width:calc(var(--ds-rule-w, 1px) * 2);
  padding-top:14px;
}


/* ---- how a new password is doing ---- */

/* The mark sits inside the field, against its right edge. The label is the
   positioning box because the input is a grid child and giving it position
   would take it out of the alignment the rest of the row uses. */
/* The box around the input, which is what the mark is positioned against - the
   label holds the words above and the helper line below, so measuring from it
   put the lock at the bottom edge of the field. */
.dst-pw-box{ position:relative; display:block }
.dst-pw-box > input{ display:block; width:100% }

.dst-pw-mark{
  position:absolute;
  right:44px;
  top:50%;
  transform:translateY(-50%);
  display:flex; align-items:center; justify-content:center;
  width:18px; height:18px;
  pointer-events:none;
  opacity:0; transition:opacity .18s ease, color .18s ease;
}

/* Nothing typed yet says nothing. A field marked red before it has been touched
   is a form telling somebody off for not having started. */
.dst-field[data-dst-pw="bad"]  .dst-pw-mark,
.dst-field[data-dst-pw="part"] .dst-pw-mark,
.dst-field[data-dst-pw="good"] .dst-pw-mark{ opacity:1 }

.dst-field[data-dst-pw="bad"]  .dst-pw-mark{ color:var(--ds-form-error,#ff5c5c) }
.dst-field[data-dst-pw="part"] .dst-pw-mark{ color:#e8a33d }
.dst-field[data-dst-pw="good"] .dst-pw-mark{ color:#3ecf8e }

/* The words are not squeezed under the mark. */
/* Room for both, and no room for a third: the browser's own reveal button sits
   in this same corner on Edge, comes and goes with focus, and is drawn to its
   own taste. Ours is always there and always the same. */
.dst-pw-box > input::-ms-reveal,
.dst-pw-box > input::-ms-clear{ display:none }

/* Room for the eye on every password field, and for the lock beside it on the
   ones that have one. */
.dst-pw-box > input{ padding-right:44px }
.dst-field.dst-pw .dst-pw-box > input{ padding-right:74px }

.dst-pw-eye{
  position:absolute;
  right:12px;
  top:50%;
  transform:translateY(-50%);
  display:flex; align-items:center; justify-content:center;
  width:26px; height:26px;
  padding:0; border:0; border-radius:6px;
  background:none;
  color:inherit;
  opacity:.55;
  cursor:pointer;
  transition:opacity .18s ease;
}

.dst-pw-eye:hover,
.dst-pw-eye:focus-visible{ opacity:1 }
.dst-pw-eye:focus-visible{ outline:2px solid currentColor; outline-offset:2px }


/* What the lock means, in words, under the field it belongs to. */
.dst-pw-says{
  display:block;
  margin-top:6px;
  font-size:12px;
  line-height:1.4;
  opacity:.75;
}
.dst-field[data-dst-pw="bad"]  .dst-pw-says{ color:var(--ds-form-error,#ff5c5c); opacity:1 }
.dst-field[data-dst-pw="part"] .dst-pw-says{ color:#e8a33d; opacity:1 }
.dst-field[data-dst-pw="good"] .dst-pw-says{ color:#3ecf8e; opacity:1 }

/* The two tables the account grew: downloads and subscriptions.
   They inherit the orders table's width and rhythm, and only say the things
   that are their own - a right aligned action column that takes no more room
   than the button in it. */
.dst-downloads td:last-child,
.dst-subs td:last-child,
.dst-downloads th:last-child,
.dst-subs th:last-child{ width:1%; white-space:nowrap; text-align:right }

.dst-subs td,
.dst-downloads td{ vertical-align:middle }

/* The cancel button sits in a table cell, so it must not stretch the row. */
.dst-subs form{ margin:0 }

/* ===========================================================================
   The account, on every tab.

   These pages were carrying whatever width their contents happened to want, so
   a table of three short columns sat in the left third of the page and the rest
   was empty. Everything in here takes the column it is given, and the tables
   are ruled row by row so a list of orders or downloads reads as a list rather
   than as words scattered across a dark field.
   ======================================================================== */
.dst-account{ width:100% }

.dst-account > *,
.dst-account form,
.dst-account table,
.dst-account .dst-fields{ width:100%; max-width:none }

/* Every table on the account, however it got there. */
.dst-account table{
  border-collapse:collapse;
  margin:0 0 var(--dst-block-gap, 36px);
}

.dst-account th,
.dst-account td{
  padding:14px 16px 14px 0;
  text-align:left;
  vertical-align:middle;
}

/* The heading row is the only one that carries weight, and its rule is the
   stronger of the two so the head reads as the head. */
.dst-account thead th{
  padding-top:0;
  font-size:12px; letter-spacing:.06em; text-transform:uppercase;
  opacity:.65; font-weight:600;
  border-bottom:1px solid var(--ds-line, color-mix(in srgb, currentColor 26%, transparent));
}

/* A rule under every row, and none under the last - the same arrangement the
   List element uses, so a table and a list look like the same product. */
.dst-account tbody tr{
  border-bottom:1px solid var(--ds-line, color-mix(in srgb, currentColor 14%, transparent));
}

/* ---- the categories list ----
 *
 * One rhythm, whatever the depth.
 *
 * These classes carried no styling at all, so the list took whatever the theme
 * gives any list: a bottom margin on every item, another on the nested list,
 * and the two adding together wherever a sub-list met the next top level name.
 * Measured on the shop sidebar that came out 4px in one place, 14 in another
 * and 28 before a new heading - which reads as a group of sub categories
 * belonging to whatever follows them rather than to the line they sit under.
 *
 * Ten pixels between every pair, stated once and from one side only so nothing
 * can add to anything else. */
.dst-catlist{
  list-style:none;
  margin:0;
  padding:0;
}

.dst-catitem{ margin:0; padding:0 }

/* No margin between items.
 *
 * The theme lays a widget's list out as a grid and spaces it with a row gap, so
 * a margin here does not replace that - it adds to it. Ten written here came
 * out as eighteen on the page, because the gap was still eight. The gap below
 * is the one number; the items carry nothing. */

/* The gap, said with enough weight to be the one that counts.
 *
 * The theme sets this on `.ds-widget ul:not(...):not(...)`, which outranks a
 * single class name, so `.dst-catlist { gap }` was written and ignored. Matched
 * against the same widget wrapper it wins on its own merits, without reaching
 * for !important. */
/* Counted to beat the theme, not guessed at.
 *
 * The theme spaces a widget list with `.ds-widget ul:not(a):not(b)` - three
 * class-level parts and an element, so 0,3,1. A single class name loses to it,
 * which is why `.dst-catlist { gap }` was written twice and ignored twice, and
 * why the top level stayed at the theme's eight while the nested lists took the
 * ten. Two :not() of our own brings this to 0,4,1 and it wins outright, without
 * reaching for !important. */
.ds-widget ul.dst-catlist:not(.ds-footer-social):not(.ds-social-inline),
.ds-widget ul.dst-catlist.is-sub:not(.ds-footer-social):not(.ds-social-inline){ gap:10px }

/* A nested list is one more item in the run, so it takes the same ten. The
   indent stays - it is what says these belong to the line above. */
.dst-catlist.is-sub{ margin:10px 0 0; padding-left:14px }

/* The last row keeps its rule.
   Dropping it is right in a long list, where the table ends where the words
   end - and wrong here, because an account tab often holds one row, and one
   row with no line under it reads as an unfinished page rather than as a
   list. The table is closed off. */

/* The last column is the one with the button in it. It takes the room the
   button needs and no more, at the right hand end where an action belongs. */
.dst-account th:last-child,
.dst-account td:last-child{ width:1%; white-space:nowrap; text-align:right; padding-right:0 }

.dst-account td:last-child form{ margin:0 }

/* Nothing to show yet. Its own line rather than a paragraph pretending to be
   a table. */
.dst-account .dst-empty{
  margin:0; padding:22px 0;
  opacity:.6;
  border-bottom:1px solid var(--ds-line, color-mix(in srgb, currentColor 14%, transparent));
}

@media (max-width:600px){
  /* Three columns of table on a phone is a column of single letters. The head
     goes, and each row becomes its own block with the label in front of the
     value. */
  .dst-account thead{ display:none }

  .dst-account tbody tr{
    display:grid; gap:2px;
    padding:14px 0;
  }

  .dst-account td{ padding:0 }
  .dst-account td:last-child{ width:auto; text-align:left; padding-top:10px }
}

/* ---------------------------------------------------------------------
 * Paying on the page
 *
 * The inputs themselves are drawn by the gateway inside frames of its own, so
 * everything here dresses the box around one - the frame carries the text and
 * this carries the background, the border and the corner, which is what makes
 * a gateway's field look like every other field on the checkout.
 * ------------------------------------------------------------------ */
.dst-paying .dst-payfor{ margin:0 0 18px }

#dst-pay-element{ display:grid; gap:12px; margin-bottom:20px }

/* Expiry and security code side by side - both are short answers, and
   stacked they leave two half-empty lines in the middle of the form. */
.dst-pay-pair{ display:grid; grid-template-columns:1fr 1fr; gap:12px }

/* The box the gateway draws into.
 *
 * PayPal's own guidance: it owns the input, the shop owns the container, and
 * the container must state a height. So everything visible is here - the
 * colour, the border, the corner - and the field inside is a plain rectangle
 * of the right colour, clipped to shape by this.
 *
 * The values are the shop's own field settings, so a card box is whatever an
 * input on this checkout is. */
#dst-pay-element .dst-field > div{
  height:var(--dst-field-h,50px);
  box-sizing:border-box;
  /* The border and the corner are drawn here and clip the frame inside them.
     The frame's own colour is flooded outward by a spread shadow on the
     input, so what is clipped is a solid field of the right colour. */
  background:var(--dst-field-bg,var(--ds-field-bg,#000));
  border:var(--dst-field-border,1px solid transparent);
  border-radius:var(--dst-field-radius,var(--ds-field-radius,4px));
  overflow:hidden;
}

/* The two ends, painted over.
 *
 * The gateway's frame holds a container of its own with a little padding at
 * each side, and that container is white. The field inside floods its colour
 * outward to cover it, but the container clips that flood at its own edge, so
 * a sliver of white was left at the left and right of the box - worst on the
 * card number, which carries a brand mark and so has more of that container
 * showing. None of it can be reached from here: it is another origin.
 *
 * So it is covered from this side. Two strips in the field's own colour, over
 * the frame and under nothing, clipped to the corner by the box. They sit on
 * padding rather than on any text, and pass every click through to the field
 * behind them. */
#dst-pay-element .dst-field > div{ position:relative }

#dst-pay-element .dst-field > div::before,
#dst-pay-element .dst-field > div::after{
  content:'';
  position:absolute; top:0; bottom:0; width:10px;
  background:var(--dst-field-bg,var(--ds-field-bg,#000));
  pointer-events:none;
  z-index:1;
}
#dst-pay-element .dst-field > div::before{ left:0 }
#dst-pay-element .dst-field > div::after{ right:0 }

/* The ring belongs to the shape, and the shape is the box. */
#dst-pay-element .dst-field > div:has(iframe:focus-within){
  border-color:var(--ds-field-focus,var(--ds-accent,#fff));
}

/* The gateway writes height:55px straight onto its own wrapper - measured,
   not guessed - and an inline style beats a stylesheet, so this is the one
   element that has to be overruled. */
/* Its own height, not ours - the script centres it in the box instead of
   squeezing it, because a frame squeezed shorter than its contents still
   lays those contents out at full size and simply clips them. */
#dst-pay-element .dst-field > div > div{
  display:block !important;
  width:100% !important;
}

/* A browser gives every iframe a 2px inset border of its own and draws it
   white. That was the thick white frame around each field - not a border
   anybody set, the one nobody turned off. */
/* No display here.
 *
 * The gateway renders two frames per field - the live one and a second it
 * keeps hidden - and display:block on every iframe un-hid the spare, which
 * then sat on top of the real one and swallowed every click. Four fields,
 * eight frames, none of them typeable. Whether a frame is shown is the
 * gateway's business; everything else here is ours. */
#dst-pay-element iframe{
  width:100% !important;
  border:0 !important;
  margin:0 !important;
  background:transparent;
}

.dst-paying .dst-dim{ margin-top:16px; opacity:.6; font-size:.9em }

/* ---------------------------------------------------------------------
 * The two buttons under a payment form, the same height
 *
 * Whatever either of them inherits, stretch makes them one height - so the
 * pair cannot come out uneven on a screen where something differs, which is
 * exactly what forcing a figure here would fail to catch. Scoped to this
 * modal, so no button anywhere else on the site changes.
 * ------------------------------------------------------------------ */
.ds-modal-panel .dst-card-does{
  display:flex !important;
  align-items:stretch !important;
  flex-wrap:wrap;
  gap:12px;
}

.ds-modal-panel .dst-card-does > .ds-btn{
  height:auto !important;
  min-height:0 !important;
  align-self:stretch !important;
  display:inline-flex !important;
  align-items:center !important;
  justify-content:center !important;
  box-sizing:border-box !important;
}

/* ------------------------------------------------------------------
 * Paging a grid of products
 *
 * The grid shows one page of columns x rows and these are the numbers
 * under it. Laid out here rather than left to inherit, or the count and
 * the links run together as one line of text.
 * --------------------------------------------------------------- */

.dst-pager{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:8px;
  margin-top:36px;
}

.dst-pager-count{
  margin-right:auto;
  opacity:.7;
  font-size:14px;
}

.dst-pager .page-numbers{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  min-width:38px;
  height:38px;
  padding:0 10px;
  border:1px solid var(--ds-line, rgba(255,255,255,.16));
  border-radius:var(--ds-field-radius, 2px);
  text-decoration:none;
  line-height:1;
}

.dst-pager .page-numbers:hover{ border-color:var(--ds-accent) }

.dst-pager .page-numbers.current{
  border-color:var(--ds-accent);
  color:var(--ds-accent);
}

.dst-pager .page-numbers.dots{ border:0; padding:0 4px }

/* The specification table, and the air in front of it.
 *
 * The specifications are a different kind of reading from the paragraph above
 * them - prose to a list of figures - so the change wants announcing. Written
 * on the heading rather than on the paragraph because the paragraph is
 * whatever the description happens to end with, and this has to hold whether
 * that is one line or six.
 *
 * The figure is fixed rather than read from a setting: the block is generated,
 * not placed, so there is nothing in the builder to set it on. */
.dst-specs-head{ margin-top:50px; margin-bottom:10px }
.dst-specs{ width:100%; border-collapse:collapse }
/* A rule under every row but the last, so the pairs read across without a box
   being drawn round them - the same line the cart and the totals already use,
   set once on General, so a spec table matches every other list on the site.
   The label column takes only what it needs and the value takes the rest,
   which is what makes the table fill the width it is given. */
.dst-specs th{
  text-align:left; padding:10px 20px 10px 0; font-weight:600;
  white-space:nowrap; vertical-align:top; width:1%;
  border-bottom:1px solid var(--ds-line, color-mix(in srgb, currentColor 14%, transparent));
}
.dst-specs td{
  padding:10px 0; vertical-align:top; width:auto;
  border-bottom:1px solid var(--ds-line, color-mix(in srgb, currentColor 14%, transparent));
}
.dst-specs tr:last-child :is(th,td){ border-bottom:0 }
