/*
Theme Name:   Darkside
Theme URI:    https://madeinthedark.com/darkside
Description:  The theme the Darkside plugin controls, and the target the Darkside generator builds into. Plain on its own - the plugin supplies the color, the type and the header.
Author:       Made In The Dark LLC
Author URI:   https://madeinthedark.com
Version: 0.2.0
Requires at least: 6.5
Requires PHP: 8.1
License:      GPL-2.0-or-later
Text Domain:  darkside
Tags:         one-column, custom-menu, custom-logo, editor-style, block-styles
*/

/* Every value here is a fallback. The plugin writes the real ones into :root as
   custom properties, so this file never has to be regenerated when a setting
   changes - and a site with the plugin switched off still renders. */
:root{
  --ds-bg:#0B0B0C; --ds-text:#F5F5F5; --ds-heading:#FFFFFF;
  --ds-link:#F5F5F5; --ds-link-hover:#FFFFFF; --ds-accent:#8A8A93;
  --ds-btn-bg:#FFFFFF; --ds-btn-text:#0B0B0C;
  --ds-line:rgba(255,255,255,.14);
  --ds-max:1200px; --ds-gutter:24px; --ds-header-h:80px;
  --ds-font-heading:system-ui,sans-serif; --ds-font-text:system-ui,sans-serif;
  /* What the theme draws with the plugin switched off. Weight 400 and no case
     change on every tag: a default must not restyle the font, and a family that
     ships one weight cannot answer 600 - the browser fakes the bold and smears
     the letterforms the designer chose. */
  --ds-h1-size:64px; --ds-h1-weight:400; --ds-h1-case:none; --ds-h1-lh:1em;
  --ds-h2-size:44px; --ds-h2-weight:400; --ds-h2-case:none; --ds-h2-lh:1em;
  --ds-h3-size:30px; --ds-h3-weight:400; --ds-h3-case:none; --ds-h3-lh:1em;
  --ds-h4-size:22px; --ds-h4-weight:400; --ds-h4-case:none; --ds-h4-lh:1em;
  --ds-h5-size:18px; --ds-h5-weight:400; --ds-h5-case:none; --ds-h5-lh:1em;
  --ds-h6-size:15px; --ds-h6-weight:400; --ds-h6-case:none; --ds-h6-lh:1em; --ds-h6-track:0.06em;
  --ds-p-size:17px;  --ds-p-weight:400;  --ds-p-case:none;  --ds-p-lh:1.4em;
}

*,*::before,*::after{ box-sizing:border-box }
/* The colour on the root as well as on the body.
   A background set only on the body is normally propagated up to the viewport
   for you - but not before the body exists, and not while a fixed wrapper and a
   fresh compositing layer are being set up, which is when the white frame at
   the start of a load comes from. Saying it here means the very first paint is
   already the site's colour. */
html{ -webkit-text-size-adjust:100%; background:var(--ds-bg,#0b0b0c) }
body{
  /* The paragraph colour is set here, not on p.
   *
   * It used to be "p { color: var(--ds-p-color) }", which put a colour on the
   * paragraph itself - and a colour on an element can never be reached from
   * anything containing it. Not by a longer selector, not by !important, not
   * by loading later; none of those cross from a parent to a child. So
   *
   *     .my-section .ds-text { color: #f3f3f3 }
   *
   * coloured the wrapper, stopped there, and left the paragraph as it was with
   * nothing in the CSS to say why. Set here instead, every paragraph inherits
   * it, and any rule written against anything above the paragraph reaches it
   * the way its author expects.
   *
   * The paragraph colour falls back to the body text colour, so a site that
   * never set one behaves exactly as it did. Elements that carry their own
   * colour - headings, links, buttons, kickers - are unaffected either way. */
  margin:0; background:var(--ds-bg); color:var(--ds-p-color, var(--ds-text));
  font-family:var(--ds-font-text); font-size:var(--ds-p-size);
  /* The paragraph line height from Theme Settings, rather than a figure fixed
     here that no setting could reach. */
  font-weight:var(--ds-p-weight); line-height:var(--ds-p-lh,1.4em);
  letter-spacing:var(--ds-p-track,0em);
  /* How the type is drawn, from Theme Settings, Typography, Performance.
     The fallbacks are what was hard coded here before the card existed,
     so the sheet on its own behaves as it always did. */
  text-rendering:var(--ds-rendering,auto);
  -webkit-font-smoothing:var(--ds-smoothing,antialiased);
  -moz-osx-font-smoothing:var(--ds-osx-smoothing,auto);
  font-optical-sizing:var(--ds-optical,auto);
}
img,svg,video{ max-width:100%; height:auto; display:block }
/* Links carry their own color and their own hover, rather than inheriting
   body text - otherwise setting a link color on the settings screen would
   visibly do nothing. */
a{ color:var(--ds-link) }
/* The second and third buttons.
 *
 * Written as the same six variables the main button already reads rather
 * than as declarations of their own - so the radius, padding, size, case,
 * speed and every hover effect stay whatever Theme Settings says. These
 * change what a button is coloured and nothing else about it.
 *
 * Every fallback is what these already looked like in the shop, so nothing
 * moves until the cards are used. */
/* Two classes, so the base .ds-btn further down this file cannot overwrite
   these. Both were (0,1,0) and the base is written later, so every variable
   set here was replaced by the default button - a button set to Secondary drew
   in the default colours and the two looked identical whatever was chosen. */
.ds-btn.ds-btn-secondary{
  --fill:var(--ds-btn2-fill, transparent);
  --edge:var(--ds-btn2-edge, var(--ds-btn-bg));
  --ink:var(--ds-btn2-ink, var(--ds-btn-bg));
  --fill-h:var(--ds-btn2-fill-hover, var(--ds-btn-bg));
  --edge-h:var(--ds-btn2-edge-hover, var(--ds-btn-bg));
  --ink-h:var(--ds-btn2-ink-hover, var(--ds-btn-text));
  background:var(--fill); color:var(--ink); border-color:var(--edge);
}

/* Same reason as Secondary above. */
.ds-btn.ds-btn-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));
  background:var(--fill); color:var(--ink); border-color:var(--edge);
}

/* Hovered, for the presets that do not animate a fill of their own. */
.ds-btn-secondary:hover,
.ds-btn-danger:hover{
  background:var(--fill-h); color:var(--ink-h); border-color:var(--edge-h);
}

/* Links in body copy.
 *
 * Scoped to the things that hold running text rather than to the page: a
 * menu item, a button, a product card and the basket are anchors too, and
 * underlining those would be a different setting nobody asked for.
 *
 * There was no rule for these at all before this card, so they took the
 * browser's underline - which is why Show is the default, and switching the
 * card on changes nothing until Remove is chosen. */
.ds-links-underline .ds-main :is(.ds-text, .ds-list, .ds-iconbox-text, .entry-content, .ds-post-body) a:not(.ds-btn){
  text-decoration:underline;
  text-underline-offset:3px;
  text-decoration-thickness:from-font;
}
.ds-links-plain .ds-main :is(.ds-text, .ds-list, .ds-iconbox-text, .entry-content, .ds-post-body) a:not(.ds-btn){
  text-decoration:none;
}

a:hover,a:focus-visible{ color:var(--ds-link-hover) }
.ds-main a{ text-underline-offset:.18em }

/* Buttons.
   Colors are palette roles; everything else is set on the Buttons tab. Written
   once here and shared by the theme, the builder and anything the editor marks
   as a button, so all three cannot drift apart. */
.wp-block-button__link,.ds-btn,button.ds-btn,
input[type=submit],button[type=submit]{
  /* A flex line, so the label sits in the middle of the button.
   *
   * inline-block puts the label and its arrow on the text baseline, and the
   * arrow's box is taller than the words - so the words were pushed down.
   * Measured on Place order: 21px above the label, 15 below, in a 53px
   * button. A rule further down already said inline-flex with align-items,
   * but this one names button.ds-btn and outranked it, so it never applied
   * to the one kind of button that is always a <button>. */
  display:inline-flex; align-items:center; justify-content:center;
  gap:var(--ds-btnicon-gap,.6em);
  padding:var(--ds-btn-pad,14px 30px);
  border-radius:var(--ds-btn-radius,2px);
  background:var(--ds-btn-bg); color:var(--ds-btn-text);
  border:var(--ds-btn-border,1px) solid var(--ds-btn-bg);
  font-family:var(--ds-btn-font, var(--ds-font-text)); font-size:var(--ds-btn-size,14px);
  font-weight:var(--ds-btn-weight,500);
  text-transform:var(--ds-btn-case,none);
  letter-spacing:var(--ds-btn-track,0em);
  line-height:1.2; text-decoration:none; cursor:pointer;
  /* The browser's own button chrome, off.
   *
   * An <a> has none, a <button> does - so the two were never the same object
   * being styled, and a native background sat under the theme's own. It is
   * what gave the shop's buttons a fill that looked like it came in from the
   * edges rather than a flat change of colour. */
  appearance:none; -webkit-appearance:none;
  transition:background var(--ds-btn-speed,.35s) ease,
             color var(--ds-btn-speed,.35s) ease,
             border-color var(--ds-btn-speed,.35s) ease,
             transform var(--ds-btn-speed,.35s) ease,
             box-shadow var(--ds-btn-speed,.35s) ease;
}
.wp-block-button__link:hover,.ds-btn:hover,button.ds-btn:hover,
input[type=submit]:hover,button[type=submit]:hover{ color:var(--ds-btn-text) }

/* one hover, chosen on the Buttons tab */
body.ds-hover-fade   .ds-btn:hover,
body.ds-hover-fade   .wp-block-button__link:hover{ opacity:.85 }
body.ds-hover-lift   .ds-btn:hover,
body.ds-hover-lift   .wp-block-button__link:hover{ transform:translateY(-2px) }
/* Default: the button wears the hover colours it was given, and nothing else.
 *
 * This rule used to read background:transparent; color:var(--ds-btn-bg) - a
 * real inversion, which is where the old name came from. For .ds-btn it never
 * showed, because the rule far below sets the same properties from the hover
 * swatches and comes later; it only ever reached the block editor's button,
 * which has no rule down there. So the two halves of one setting disagreed, and
 * a block button inverted while a theme button changed colour.
 *
 * Both say the same thing now. "invert" is the old stored name and is kept
 * beside it so a site that has not resaved its settings keeps its hover. */
body.ds-hover-default .ds-btn:hover,
body.ds-hover-default .wp-block-button__link:hover,
body.ds-hover-invert .ds-btn:hover,
body.ds-hover-invert .wp-block-button__link:hover{
  background:var(--fill-h); color:var(--ink-h); border-color:var(--edge-h) }

/* Form fields.
   Each color falls back to the page rather than being set, so a site that
   changes its palette does not leave the forms behind on the old one. */
.ds-form-field,
input[type=text],input[type=email],input[type=url],input[type=tel],
input[type=number],input[type=password],input[type=search],input[type=date],
textarea,select{
  width:100%; max-width:100%;
  padding:var(--ds-field-pad,12px 14px);
  border-radius:var(--ds-field-radius,2px);
  /* A width per side, so a field can be a rule under the words rather than
     a box round them. The colour and the style stay one for all four - a
     border that is dashed on one edge and solid on the next is not a thing
     anybody asked for. --ds-field-border is the fallback, which is what a
     site that never opened this card is still using. */
  border-style:solid;
  border-color:var(--ds-field-line, var(--ds-line));
  border-width:var(--ds-field-border-side, var(--ds-field-border,1px));
  background:var(--ds-field-bg, transparent);
  color:var(--ds-field-text, var(--ds-text));
  font-family:var(--ds-font-text); font-size:var(--ds-field-size,15px);
  line-height:1.4;
  transition:border-color .16s ease, box-shadow .16s ease;
}
/* Rows rather than a height in pixels: a textarea opens at the number of
   lines somebody asked for, whatever size the type is set at.

   A height rather than a minimum. Every form plugin writes a rows attribute
   of its own - Contact Form 7 sends 10 - and that is an intrinsic height, so
   a minimum below it did nothing and asking for three rows left a ten row
   box. The line box is 1.4, which is what the rule above sets, and the
   padding is the two figures from the Textarea card added up. */
textarea{
  height:calc(var(--ds-ta-rows,6) * 1.4em + var(--ds-ta-pad-y,24px));
  min-height:calc(var(--ds-ta-rows,6) * 1.4em + var(--ds-ta-pad-y,24px));
  /* Only where Columns was given a figure. A ch is the width of a zero in
     the face being used, which is what a textarea column has always meant. */
  max-width:calc(var(--ds-ta-cols, 999) * 1ch);
  padding:var(--ds-ta-pad, var(--ds-field-pad));
  resize:vertical }

/* The open list is drawn by the operating system, not by the page, so it takes
 * colours of its own from Forms - Fields - Select rather than inheriting the
 * field's.
 *
 * It used to follow the field, and a field background of transparent is a
 * perfectly good field and an unreadable list: the system falls back to white
 * and puts the field's white text on it, which is what the shop's filters were
 * doing. These fall back to the field only when nothing has been chosen, so a
 * site that never opens the card behaves exactly as it did.
 *
 * background-color rather than the background shorthand - the shorthand also
 * clears background-image, which some engines use to draw the row highlight. */
/* The popup panel itself - its frame, scrollbar and the gap around the rows -
   is chrome that CSS cannot reach. color-scheme is the one property that can,
   and the theme sets it from the option background so a dark list does not open
   inside a white box. */
select{ color-scheme:var(--ds-opt-scheme, normal) }

select option,select optgroup{
  /* The page background, not the field's - a field is very often
     transparent, and a transparent option is a white one. */
  background-color:var(--ds-opt-bg, var(--ds-bg, #111));
  color:var(--ds-opt-text, var(--ds-field-text, var(--ds-text))) }

/* The row under the pointer and the row already chosen.
 *
 * Engines disagree about this more than anywhere else in a form. Firefox
 * honours option:hover and the background-color below. Chrome and Safari hand
 * the highlighted row to the system and ignore both - but they do draw an inset
 * box-shadow, which is why one is written here at a spread wide enough to fill
 * the row. Naming :checked as well covers the row the list opens on, which is
 * the one case every engine does paint. */
select option:checked,
select option:hover,
select option:focus{
  background-color:var(--ds-opt-bg-hover, var(--ds-field-focus, var(--ds-link)));
  color:var(--ds-opt-text-hover, var(--ds-btn-text, var(--ds-bg)));
  box-shadow:0 0 0 100px var(--ds-opt-bg-hover, var(--ds-field-focus, var(--ds-link))) inset }


}
/* The same box as an input, on every engine.

   appearance:none is the standard property and the only one modern Chrome
   and Firefox need. The two prefixes are for the Safari and Firefox versions
   that shipped before it, which otherwise keep the operating system's own
   control - rounded, grey, and nothing like the field beside it. ::-ms-expand
   is the arrow legacy Edge draws on top of ours whatever appearance says.

   The colour, the border, the radius and the type all come from the rule at
   the top that names select alongside input and textarea, so there is one
   description of a field and this only takes the chrome off. */
select{
  -webkit-appearance:none; -moz-appearance:none; appearance:none;
  background-image:linear-gradient(45deg,transparent 50%,currentColor 50%),
                   linear-gradient(135deg,currentColor 50%,transparent 50%);
  background-position:calc(100% - 20px) calc(50% + 2px),calc(100% - 15px) calc(50% + 2px);
  background-size:5px 5px,5px 5px; background-repeat:no-repeat;
  padding-right:44px }


/* One rule per syntax, never grouped. A selector an engine does not understand
   invalidates the whole rule it is in, so grouping these would silently drop
   the placeholder color in whichever browser did not know one of them.
   Firefox also dims placeholders by default, hence opacity on every rule. */
::placeholder{ color:var(--ds-field-hint, var(--ds-accent)); opacity:1 }
::-webkit-input-placeholder{ color:var(--ds-field-hint, var(--ds-accent)); opacity:1 }
::-moz-placeholder{ color:var(--ds-field-hint, var(--ds-accent)); opacity:1 }
:-ms-input-placeholder{ color:var(--ds-field-hint, var(--ds-accent)); opacity:1 }

/* ---- Contact Form 7 ----
   Its fields are plain input and textarea, so they already match. What does not
   is everything CF7 draws itself: the validation tips, the response line and
   the spinner. Left alone they arrive with the plugin's own red-on-white look,
   which belongs to no site. */
.wpcf7-form p{ margin:0 0 var(--ds-field-gap,18px) }
.wpcf7-form-control-wrap{ display:block }

.wpcf7-not-valid-tip{ display:block; margin-top:6px;
  font-size:13px; color:var(--ds-form-error,#ff5c5c) }
.wpcf7-form-control.wpcf7-not-valid{ border-color:var(--ds-form-error,#ff5c5c) }

/* ---- the spinner in the button ---- */
/* The submit has to lay its children out in a row for a spinner to sit beside
   the words. .ds-btn already says inline-flex, but button[type=submit] in the
   button block above is more specific and was winning with inline-block. */
button.wpcf7-submit{ display:inline-flex; align-items:center; justify-content:center }
/* One shape, drawn from currentColor, so it matches whatever the button's ink
   is without a second color setting to keep in step. */
.ds-btn-spin{ display:inline-block; flex:0 0 auto; width:1em; height:1em;
  opacity:0; transition:opacity .2s ease, width .2s ease, margin .2s ease;
  width:0; margin:0;
  /* Out of the line until it is wanted.
     The button is a flex row with a 9px gap, and a gap is spent on every item
     including one that is nought pixels wide - so a button with a spinner
     carried 9px of empty space to the right of its label and the words sat off
     centre. Absolute takes it out of the flow, so it costs nothing until the
     sending class moves it back in. */
  position:absolute; right:0 }
.wpcf7-submit.is-sending .ds-btn-spin{ position:static }
.wpcf7-submit.is-sending .ds-btn-spin{ opacity:1; width:1.05em; height:1.05em }
.ds-btn-spin-right.is-sending .ds-btn-spin{ margin-left:.6em }
.ds-btn-spin-left.is-sending  .ds-btn-spin{ margin-right:.6em }

/* On its own: the words go, the button keeps its width. */
.ds-btn-spin-only.is-sending .ds-btn-label{ visibility:hidden }
.ds-btn-spin-only.is-sending .ds-btn-spin{ position:absolute; left:50%; top:50%;
  margin:0; transform:translate(-50%,-50%) }
.ds-btn-spin-only{ position:relative }

.wpcf7-submit.is-sending{ cursor:progress }

/* Contact Form 7's own spinner, where that is the one in use.
 *
 * The Buttons tab can leave cf7's spinner alone rather than putting the theme's
 * in its place, and cf7 draws that one in two hard coded greys - a dark disc
 * with a pale dot travelling round it. On a lime button with black lettering
 * that is a grey blob belonging to no part of the site.
 *
 * currentColor for both, so it is the button's own ink whatever the button is:
 * the disc a fraction of it for the track, the dot at full strength. Marked
 * important because cf7 sets these on the element's own class too. */
.wpcf7-spinner{
  background-color:color-mix(in srgb, currentColor 22%, transparent) !important;
}
.wpcf7-spinner::before{
  background-color:currentColor !important;
}

/* The shape inside a submit button is the same shape the preloader draws.

   There used to be a second, cruder set of drawings here - one circle standing
   in for the double ring, a single dot standing in for both Three dots and
   Bars, and nothing at all for the six shapes added later, which came out as an
   empty box. The preloader's own rules cover all twelve and are already on the
   page, so the button borrows them: this only says how big, and in what colour.

   The shape sits inside .ds-btn-spin rather than being that element, which is
   what keeps it clear of the preloader's own rings. */
.ds-btn-spin{ display:inline-grid; place-items:center; color:inherit }

/* The size and colour are set on the shape itself, not on the wrapper.
   The preloader declares --ds-spin on .ds-spin - its own size, which is 96px on
   this site - so a variable inherited from the wrapper was overruled the moment
   it reached the shape, and a button spinner came out 96 pixels across. This is
   the more specific rule, so it wins. */
.ds-btn-spin > .ds-spin{
  --ds-spin:1.05em; --c:currentColor;
  width:var(--ds-spin); height:var(--ds-spin);
  display:grid; place-items:center; color:inherit }
/* Two of them lay their pieces out in a row and are sized by the pieces, so
   they take the height from here rather than from a fixed figure. */
.ds-btn-spin > .ds-spin-dots{ display:flex; gap:calc(var(--ds-spin) * .18) }
.ds-btn-spin > .ds-spin-bars{ display:flex; gap:calc(var(--ds-spin) * .12);
  height:var(--ds-spin) }
.ds-btn-spin > .ds-spin-bars i{ width:calc(var(--ds-spin) * .16) }
/* The ring's border is a flat 3px, which on a shape this small is a third of
   its width - a doughnut with barely a hole, where the one arc that is meant
   to be seen travelling round cannot be picked out from the track it runs on.
   Proportional here, with a floor so it never thins to nothing. */
.ds-btn-spin > .ds-spin-ring{ border-width:max(1.5px, calc(var(--ds-spin) * .13)) }

@media (prefers-reduced-motion: reduce){
  .ds-btn-spin{ animation:none !important }
}

/* ---- the growler ---- */
/* The gap to the edge of the viewport is the page gutter, so a growler lines up
   with the content beside it instead of sitting at its own fixed twenty. */
.ds-growl-deck{ position:fixed; z-index:99998; display:grid; gap:10px;
  max-width:min(380px,calc(100vw - var(--ds-gutter,24px) * 2)); pointer-events:none }
.ds-growl-top-left    { top:var(--ds-gutter,24px); left:var(--ds-gutter,24px) }
.ds-growl-top-right   { top:var(--ds-gutter,24px); right:var(--ds-gutter,24px) }
.ds-growl-bottom-left { bottom:var(--ds-gutter,24px); left:var(--ds-gutter,24px) }
.ds-growl-bottom-right{ bottom:var(--ds-gutter,24px); right:var(--ds-gutter,24px) }
.ds-growl-middle-right{ top:50%; right:var(--ds-gutter,24px); transform:translateY(-50%) }
/* Centred on the viewport, not on what is left of it after the gutter. */
.ds-growl-bottom-center{ bottom:var(--ds-gutter,24px); left:50%; transform:translateX(-50%) }

/* Its own colors, falling back to the inline reply's so a site that only sets
   one gets a growler that matches it. */
.ds-growl{ padding:var(--ds-growl-pad, var(--ds-resp-pad,12px 16px));
  background:var(--ds-growl-bg, var(--ds-resp-bg, var(--ds-bg)));
  color:var(--ds-growl-text, var(--ds-resp-text, var(--ds-text)));
  border:1px solid var(--ds-growl-line, var(--ds-resp-line, var(--ds-line)));
  /* Its own corner, not the field radius. A growler is a card that appears
     over the page, and the roundness that suits an input rarely suits one. */
  border-radius:var(--ds-growl-radius, var(--ds-field-radius,2px));
  font-size:14px; line-height:1.5;
  box-shadow:0 24px 60px -20px rgba(0,0,0,.6);
  opacity:0; transform:translateY(10px);
  transition:opacity .28s ease, transform .28s cubic-bezier(.22,1,.36,1) }
.ds-growl.is-up{ opacity:1; transform:none }
/* A failed one has its own three colours, each falling back to the growler's
   when it is not set. It used to take the error colour for its edge and nothing
   else, so a growler border changed nothing anybody could see: a form that
   cannot send - which is every form on a machine with no mail - only ever
   raises this one. */
.ds-growl-bad{
  background:var(--ds-growl-err-bg, var(--ds-growl-bg, var(--ds-resp-bg, var(--ds-bg))));
  color:var(--ds-growl-err-text, var(--ds-growl-text, var(--ds-resp-text, var(--ds-text))));
  border-color:var(--ds-growl-err-line, var(--ds-err-line, var(--ds-form-error,#ff5c5c))) }

/* Icons off: whatever CF7 draws beside a reply or a rejected field goes, and
   the words close the gap it left. Written for the mark however it arrives -
   as an image, as a glyph on a pseudo element, or as CF7's own icon span. */
.ds-cf7-noicons .wpcf7-response-output::before,
.ds-cf7-noicons .wpcf7-response-output::after,
.ds-cf7-noicons .wpcf7-not-valid-tip::before,
.ds-cf7-noicons .wpcf7-not-valid-tip::after{ content:none !important; display:none !important }
.ds-cf7-noicons .wpcf7-response-output > img,
.ds-cf7-noicons .wpcf7-response-output > svg,
.ds-cf7-noicons .wpcf7-response-output .wpcf7-icon,
.ds-cf7-noicons .wpcf7-not-valid-tip > img,
.ds-cf7-noicons .wpcf7-not-valid-tip > svg,
.ds-cf7-noicons .wpcf7-not-valid-tip .wpcf7-icon,
.ds-cf7-noicons .wpcf7-response-output img.emoji,
.ds-cf7-noicons .wpcf7-not-valid-tip img.emoji{ display:none !important }

/* Replaced by the growler, not shown as well as it. */
.wpcf7-response-output.ds-resp-off{ position:absolute; width:1px; height:1px;
  overflow:hidden; clip-path:inset(50%); white-space:nowrap; border:0; padding:0 }

.wpcf7-response-output{ margin:var(--ds-field-gap,18px) 0 0; padding:var(--ds-resp-pad,12px 16px);
  background:var(--ds-resp-bg, transparent);
  border:1px solid var(--ds-resp-line, var(--ds-line));
  color:var(--ds-resp-text, inherit);
  border-radius:var(--ds-field-radius,2px); font-size:14px }

/* A failed submit has its own three colors, each falling back to the reply's
   when it is not set - so a site that only wants one loud edge still gets one,
   and a site that wants the whole message loud can have that too. */
.wpcf7-form.invalid .wpcf7-response-output,
.wpcf7-form.unaccepted .wpcf7-response-output,
.wpcf7-form.spam .wpcf7-response-output{
  background:var(--ds-err-bg, var(--ds-resp-bg, transparent));
  border-color:var(--ds-err-line, var(--ds-form-error,#ff5c5c));
  color:var(--ds-form-error, var(--ds-resp-text, inherit)) }

.wpcf7-list-item{ margin:0 18px 0 0 }
.wpcf7-spinner{ margin:0 0 0 12px }
/* Ours replaces it rather than joining it. */
.ds-spin-mine .wpcf7-spinner{ display:none }

/* A spinner outside the button, where CF7's own used to sit. */
.ds-spin-at-right{ display:inline-flex; align-items:center; gap:12px }
.ds-spin-at-bottom{ display:inline-flex; flex-direction:column; align-items:flex-start; gap:12px }
.ds-spin-beside{ width:1.1em; height:1.1em; opacity:0;
  transition:opacity .2s ease; color:inherit }
.is-sending .ds-spin-beside{ opacity:1 }

/* Set by the Form labels row in Typography, so a field label on a contact form,
   at the checkout and over a product's Size picker are one decision. */
label,.ds-label{ display:block; margin:var(--ds-label-margin,0 0 6px 0);
  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);
  color:var(--ds-text) }
.ds-field,p:has(> label){ margin-bottom:var(--ds-field-gap,18px) }

/* Two ways a label is written, and the same spacing out of both.

   Written separately - <label>Name</label><input> - the label's own bottom
   margin is the gap, and nothing else is needed.

   Written wrapping the field, which is what Contact Form 7 does, there is
   nothing between the words and the control for a margin to push apart. The
   gap moves to the control, and the label's bottom margin is dropped so the
   same value is not also counted underneath the field. */
label > .wpcf7-form-control-wrap,
label > input:not([type=checkbox]):not([type=radio]),
label > textarea,
label > select{ display:block; margin-top:var(--ds-label-gap,6px) }

label:has(> .wpcf7-form-control-wrap),
label:has(> input:not([type=checkbox]):not([type=radio])),
label:has(> textarea),
label:has(> select){ margin-bottom:0 }

/* Checkboxes and radios, drawn rather than left to the browser.
   accent-color gets the tick close but cannot touch the box, its border or its
   radius, so a form that matches the palette everywhere else still had two
   controls that looked like the operating system. */
input[type=checkbox],input[type=radio]{
  appearance:none; -webkit-appearance:none;
  width:var(--ds-check-size,18px); height:var(--ds-check-size,18px);
  flex:0 0 auto; margin:0; padding:0;
  display:inline-grid; place-content:center;
  border:var(--ds-field-border,1px) solid var(--ds-field-line, var(--ds-line));
  background:var(--ds-field-bg, transparent);
  border-radius:var(--ds-field-radius,2px);
  cursor:pointer; vertical-align:middle;
  transition:background .16s ease, border-color .16s ease;
}
/* The radio takes its own size, falling back to the checkbox's - the two
   share every other rule above, and only the width, the height and the mark
   inside differ. */
input[type=radio]{
  border-radius:50%;
  width:var(--ds-radio-size, var(--ds-check-size,18px));
  height:var(--ds-radio-size, var(--ds-check-size,18px)) }

input[type=checkbox]::before,input[type=radio]::before{
  content:''; transition:transform .14s ease }

/* The tick is two borders rotated, so it scales with the box and needs no
   image or font. */
input[type=checkbox]::before{
  width:calc(var(--ds-check-size,18px) * .5);
  height:calc(var(--ds-check-size,18px) * .26);
  margin-top:calc(var(--ds-check-size,18px) * -.1);
  border-left:2px solid var(--ds-btn-text,#0b0b0c);
  border-bottom:2px solid var(--ds-btn-text,#0b0b0c);
  transform:rotate(-45deg) scale(0);
}
input[type=radio]::before{
  width:calc(var(--ds-radio-size, var(--ds-check-size,18px)) * .45);
  height:calc(var(--ds-radio-size, var(--ds-check-size,18px)) * .45);
  border-radius:50%; background:var(--ds-btn-text,#0b0b0c); transform:scale(0);
}

input[type=checkbox]:checked,input[type=radio]:checked{
  background:var(--ds-field-focus, var(--ds-link));
  border-color:var(--ds-field-focus, var(--ds-link)) }
input[type=checkbox]:checked::before{ transform:rotate(-45deg) scale(1) }
input[type=radio]:checked::before{ transform:scale(1) }

input[type=checkbox]:focus-visible,input[type=radio]:focus-visible{
  outline:2px solid var(--ds-field-focus, var(--ds-link)); outline-offset:2px }
input[type=checkbox]:disabled,input[type=radio]:disabled{ opacity:.5; cursor:default }

/* Its own spacing, because this label sits beside its box and beside the next
   option rather than stacked above a field. inline-flex so a row of options
   stays a row. */
label:has(input[type=checkbox]),label:has(input[type=radio]){
  display:inline-flex; align-items:center; gap:8px; font-weight:400;
  margin:var(--ds-check-margin,0 18px 8px 0) }

/* ---- column shortcodes ----
   [one_half] ÃƒÆ’Ã†â€™Ãƒâ€ Ã¢â‚¬â„¢ÃƒÆ’Ã¢â‚¬Å¡Ãƒâ€šÃ‚Â¢ÃƒÆ’Ã†â€™Ãƒâ€šÃ‚Â¢ÃƒÆ’Ã‚Â¢ÃƒÂ¢Ã¢â‚¬Å¡Ã‚Â¬Ãƒâ€¦Ã‚Â¡ÃƒÆ’Ã¢â‚¬Å¡Ãƒâ€šÃ‚Â¬ÃƒÆ’Ã†â€™ÃƒÂ¢Ã¢â€šÂ¬Ã…Â¡ÃƒÆ’Ã¢â‚¬Å¡Ãƒâ€šÃ‚Â¦ [one_half_last] and friends. There is no wrapper by design, so
   the columns float and the last one of a row clears them. */
/* The space between two columns is Forms - Inputs - Between columns, and the
   row gutter from General - Layout until somebody sets it. One name, read
   five times below, so the widths and the margin cannot disagree. */
.ds-col-half,.ds-col-third,.ds-col-twothird,.ds-col-fourth{
  --ds-col-space:var(--ds-form-col-gap, var(--ds-gutter,24px));
  float:left; margin-right:var(--ds-col-space); min-width:0 }
.ds-col-half    { width:calc(50%      - (var(--ds-col-space) * 1 / 2)) }
.ds-col-third   { width:calc(33.3333% - (var(--ds-col-space) * 2 / 3)) }
.ds-col-twothird{ width:calc(66.6666% - (var(--ds-col-space) * 1 / 3)) }
.ds-col-fourth  { width:calc(25%      - (var(--ds-col-space) * 3 / 4)) }
.ds-col-last{ margin-right:0 }
.ds-col-clear{ clear:both; height:0; font-size:0; line-height:0 }

/* A column ends where a field ends, so a row of columns is followed by the same
   gap as the field above it rather than by nothing. */
.ds-col-half,.ds-col-third,.ds-col-twothird,.ds-col-fourth{
  margin-bottom:var(--ds-field-gap,18px) }

/* Two columns of a form on a phone is two columns of nothing. */
@media (max-width:640px){
  .ds-col-half,.ds-col-third,.ds-col-twothird,.ds-col-fourth{
    float:none; width:100%; margin-right:0 }
}

/* Line height is set per tag rather than once for all six, because a heading
   and a paragraph are doing different jobs: a heading is a few words looked at,
   a paragraph is lines read one after another. The figure comes from Theme
   Settings, Typography. */
/* The gap underneath is Typography, Performance. Half an em unless a figure has
   been set there - an em grows with the heading, which is right until somebody
   wants the same few pixels under every size. */
h1,h2,h3,h4,h5,h6{ font-family:var(--ds-font-heading); color:var(--ds-heading);
  margin:0 0 var(--ds-h-mb,.5em); line-height:var(--ds-h-lh,1em) }
h1{ color:var(--ds-h1-color, var(--ds-heading)); font-size:var(--ds-h1-size); font-weight:var(--ds-h1-weight); text-transform:var(--ds-h1-case); line-height:var(--ds-h1-lh,1em); letter-spacing:var(--ds-h1-track,0em);
    margin-block:var(--ds-h1-mt, revert) var(--ds-h1-mb, revert) }
h2{ color:var(--ds-h2-color, var(--ds-heading)); font-size:var(--ds-h2-size); font-weight:var(--ds-h2-weight); text-transform:var(--ds-h2-case); line-height:var(--ds-h2-lh,1em); letter-spacing:var(--ds-h2-track,0em);
    margin-block:var(--ds-h2-mt, revert) var(--ds-h2-mb, revert) }
h3{ color:var(--ds-h3-color, var(--ds-heading)); font-size:var(--ds-h3-size); font-weight:var(--ds-h3-weight); text-transform:var(--ds-h3-case); line-height:var(--ds-h3-lh,1em); letter-spacing:var(--ds-h3-track,0em);
    margin-block:var(--ds-h3-mt, revert) var(--ds-h3-mb, revert) }
h4{ color:var(--ds-h4-color, var(--ds-heading)); font-size:var(--ds-h4-size); font-weight:var(--ds-h4-weight); text-transform:var(--ds-h4-case); line-height:var(--ds-h4-lh,1em); letter-spacing:var(--ds-h4-track,0em);
    margin-block:var(--ds-h4-mt, revert) var(--ds-h4-mb, revert) }
h5{ color:var(--ds-h5-color, var(--ds-heading)); font-size:var(--ds-h5-size); font-weight:var(--ds-h5-weight); text-transform:var(--ds-h5-case); line-height:var(--ds-h5-lh,1em); letter-spacing:var(--ds-h5-track,0em);
    margin-block:var(--ds-h5-mt, revert) var(--ds-h5-mb, revert) }
/* The colour each text row can set, alongside the six above.
 *
 * Blank writes no variable, so the palette keeps the tag exactly as it had it.
 * These sit at one class or one tag, the same weight as the rules that set the
 * size, so an element naming its own colour still wins - that is somebody being
 * more specific than "every paragraph".
 *
 * There is no rule for p. The paragraph colour is set on body, where every
 * paragraph inherits it and a rule written against a section can still reach
 * it - see the note there. */
.ds-text-large{ color:var(--ds-text-large-color, inherit) }
.ds-text-medium{ color:var(--ds-text-medium-color, inherit) }
.ds-text-small{ color:var(--ds-text-small-color, inherit) }
.ds-kicker{ color:var(--ds-kicker-color, inherit) }

/* [ds-accent] - a word picked out in the site's accent colour.
 *
 * Inherits everything else on purpose. It marks a word inside a heading, a
 * paragraph or a kicker, and it has to keep the size, weight and face of
 * whatever it is standing in the middle of - the colour is the whole of the
 * difference. */
.ds-accent,
.ds-accent-text{ color:var(--ds-accent, currentColor) }

/* The other half of the pair the editor's "Coloring text" helper offers.
 *
 * That helper has always shown <span class="ds-accent"> and
 * <span class="ds-secondary"> as the way to colour a word, and neither class
 * was styled anywhere - so following the instructions in the panel produced no
 * colour at all. Both are real now, and [ds-accent] writes the same .ds-accent
 * the helper names, so the shortcode and the typed span are one system rather
 * than two that look alike. */
.ds-secondary{ color:var(--ds-secondary, var(--ds-accent, currentColor)) }

/* h6's tracking came from here, at .06em, with nothing in the settings to say
   so - it was drawn as an uppercase eyebrow label once and kept the spacing
   after the uppercase went. It is a setting now, and 0.06em is its default, so
   the tag looks the same as it did and can finally be changed. */
h6{ color:var(--ds-h6-color, var(--ds-heading)); font-size:var(--ds-h6-size); font-weight:var(--ds-h6-weight); text-transform:var(--ds-h6-case);
    line-height:var(--ds-h6-lh,1em); letter-spacing:var(--ds-h6-track,0.06em) }

.ds-shell{ width:100%; max-width:var(--ds-max); margin-inline:auto; padding-inline:var(--ds-gutter) }

/* The bars answer to themselves.

   The gutter is the page body's measure - the builder's rows and what is
   written in them. A header, a top bar and a footer are furniture around
   that, and each is now free to sit closer to the edge or further from it
   without moving the content.

   Each falls back to the gutter, so a site that has set none of them looks
   exactly as it did before they existed. */
.ds-header > .ds-shell{ padding-inline:var(--ds-head-gutter, var(--ds-gutter)) }
.ds-bar .ds-shell{ padding-inline:var(--ds-bar-gutter, var(--ds-gutter)) }
.ds-footer > .ds-shell{ padding-inline:var(--ds-foot-gutter, var(--ds-gutter)) }
.ds-skip{ position:absolute; left:-9999px }
.ds-skip:focus{ left:8px; top:8px; z-index:200; padding:10px 14px; background:var(--ds-btn-bg); color:var(--ds-btn-text) }

/* ---- header ---- */
/* The height above is the content area, so padding adds to it rather than being
   swallowed by a fixed height. Zero padding leaves the header exactly as tall
   as it always was. */
.ds-header{
  min-height:calc(var(--ds-header-h) + var(--ds-header-pt,0px) + var(--ds-header-pb,0px));
  padding-top:var(--ds-header-pt,0px); padding-bottom:var(--ds-header-pb,0px);
  display:flex; align-items:center;
  /* Nothing, until the Background list on the Header screen says otherwise.

     This painted the page colour whatever that list said, so None was an
     opaque panel that happened to match the page - which is invisible until
     something is meant to show through it. The title band's shadow reaches a
     few pixels above the band, and the header was sitting on top of that at
     z-index 50 and covering it.

     .ds-headbg-color and .ds-headbg-image below paint it when one is
     chosen. */
  background:transparent; position:relative; z-index:50;
  /* Set in Theme Settings. Zero width is no border at all rather than a 0px
     one, so it never counts in the header's height. */
  border-bottom:var(--ds-header-line, 0 solid transparent) }
.ds-header > .ds-shell{ display:flex; align-items:center; gap:24px; width:100% }

/* The bar mixed with what is behind it, from Header, Layout.
 *
 * On the header itself rather than on the page, so only the bar blends and the
 * content under it is left alone. z-index makes a stacking context, and a blend
 * only reaches as far as its nearest one - so the header is taken out of the
 * one it was in and left to mix with the page, which is the point.
 *
 * Difference is the one worth having: a white bar over a picture inverts
 * whatever it crosses, so the logo and the links read over the light parts and
 * the dark parts both without a panel behind them. */
body[class*="ds-headblend-"] .ds-header{ isolation:auto; z-index:auto; position:relative }
.ds-headblend-difference .ds-header{ mix-blend-mode:difference }
.ds-headblend-exclusion  .ds-header{ mix-blend-mode:exclusion }
.ds-headblend-multiply   .ds-header{ mix-blend-mode:multiply }
.ds-headblend-screen     .ds-header{ mix-blend-mode:screen }
.ds-headblend-overlay    .ds-header{ mix-blend-mode:overlay }
.ds-headblend-luminosity .ds-header{ mix-blend-mode:luminosity }
.ds-header-sticky .ds-header{ position:sticky; top:0 }

/* And what it becomes once it is over the content rather than above it.
 *
 * Every one of these falls back to what the header already is, so a sticky
 * header nobody has dressed looks the same all the way down the page - which is
 * what it did before these settings existed. The class arrives from menu.js,
 * which watches a marker at the top of the page: position:sticky has no state
 * of its own to style, so something has to say when it is actually stuck.
 *
 * Transitioned, because a header that changes between one frame and the next
 * reads as the page jumping rather than as the header responding. */
.ds-header-sticky .ds-header{
  transition:height .28s cubic-bezier(.22,1,.36,1),
             background-color .28s ease,
             backdrop-filter .28s ease,
             border-color .28s ease;
}

.ds-header-stuck .ds-header{
  height:var(--ds-stuck-h, var(--ds-header-h, 80px));
  background-color:var(--ds-stuck-bg, transparent);
  border-bottom:var(--ds-stuck-lw, 0) solid var(--ds-stuck-line, transparent);
}

/* Only where a figure was given, which is what the body class says.
 *
 * An always-on backdrop-filter puts the header on a compositing layer of its
 * own on every site whether or not anything was asked for, and that costs a
 * repaint of the strip on every frame of every scroll. It cannot be written as
 * a variable with a nought fallback either - blur(0) is still a filter, and
 * still makes the layer. */
.ds-stuck-blurs.ds-header-stuck .ds-header{
  backdrop-filter:blur(var(--ds-stuck-blur));
  -webkit-backdrop-filter:blur(var(--ds-stuck-blur));
}

.ds-stuck-blends.ds-header-stuck .ds-header{
  background-blend-mode:var(--ds-stuck-blend);
}

@media (prefers-reduced-motion: reduce){
  .ds-header-sticky .ds-header{ transition:none }
}

/* Transparent only where something sits behind it. The plugin decides that and
   sets the body class - the header does not guess. */
/* Above the content, not merely on top of it in source order.
   A row with a background sets position and isolation to stack its own media
   under its own text, and an absolutely positioned header with no z-index is
   painted over by any positioned element that comes later in the document - so
   the header vanished behind the first row's picture. */
.ds-header-transparent .ds-header{ position:absolute; inset:0 0 auto;
  background:transparent; z-index:50 }

/* A transparent header starts below the top bar, not at the top of the page.
 *
 * It is taken out of the flow, so it sat over the bar and the two read as one
 * thing overlapping rather than a bar with a header under it - the bar looked
 * like it had pushed the header up. The offset is the bar's own height, so it
 * follows the height setting without a second number to keep in step.
 *
 * Only where a bar is actually drawn: --ds-bar-h is set whatever the switch
 * says, so the class on the body is what decides, not the variable. */
.ds-has-bar.ds-header-transparent .ds-header{ top:var(--ds-bar-h,0px) }
/* Transparent decides the background and that the header overlays the content.
   Whether it stays put as the page moves is the Sticky setting, and the two are
   kept separate so either can be used without the other. Fixed rather than
   sticky here because sticky does nothing to an absolutely positioned box. */
.ds-header-transparent.ds-header-sticky .ds-header{
  position:fixed; top:0; left:0; right:0 }

/* Fixed and sticking with the bar: the header sits under it and stays there.
   Fixed and the bar scrolls away: the header goes to the top, because there is
   nothing above it any more once the bar has gone. */
.ds-has-bar.ds-bar-sticks.ds-header-transparent.ds-header-sticky .ds-header{
  top:var(--ds-bar-h,0px) }

/* The bar sticks too, which is what "With header" was always meant to mean.
 *
 * The setting has emitted ds-bar-sticks all along and the only rule reading it
 * was the one above, which offsets a transparent header - so on every ordinary
 * header the option did nothing at all and the bar scrolled away exactly as
 * "Scrolls away" does. The bar itself was never told to stick.
 *
 * Above the header in the stack, because it is above it on the page and the
 * header comes up under it. The header sits at 50 and the bar at 9, which is
 * the right way round while the header is the thing floating over the content
 * and the wrong way round once both are held at the top - so the bar is lifted
 * past it, and only in this combination. */
.ds-has-bar.ds-bar-sticks.ds-header-sticky .ds-bar{
  position:sticky; top:0; z-index:51;
}

/* How much is held at the top of the window before the header begins.
 *
 * Nought normally: a bar that scrolls away is not in anybody's way by the time
 * something comes to rest against the header, and counting it would leave a
 * band of empty screen above every sticky element on the site.
 *
 * Published as one figure so that everything which has to clear the header can
 * add it without each of them having to know the rule - the builder's sticky
 * columns read it in CSS, and sticky.js does the same sum for the ones it
 * drives. */
body{ --ds-pinned-top:0px }
body.ds-has-bar.ds-bar-sticks.ds-header-sticky{ --ds-pinned-top:var(--ds-bar-h,0px) }

/* And the header stops below it rather than sliding under the top of the
   window. Written for the ordinary header; the transparent one is handled by
   the rule above, which does the same thing for a header that is out of the
   flow. */
.ds-has-bar.ds-bar-sticks.ds-header-sticky:not(.ds-header-transparent) .ds-header{
  top:var(--ds-bar-h,0px);
}

/* The marker menu.js watches sits at the very top of the page, so a stuck
   header is detected the moment the bar starts to move rather than when the
   header itself reaches the top. With the bar held up there as well, the two
   arrive together and the reading is right for both. */

/* No negative margin. The header is absolutely positioned, so it is already out
   of the flow and the content already starts at the top of the page - pulling
   it up by the header height again moved the first row off the top of the
   window, taking the top of the hero with it. */
.ds-header-transparent .ds-main{ margin-top:0 }

/* But only a page built to run underneath it should.
 *
 * A transparent header is lifted out of the flow so a hero can fill the window
 * with the menu floating over it. Every other page got the same treatment and
 * had no hero to spare: the shop's first row of products, a post's first
 * paragraph and the Terms heading all started at the top of the window with a
 * 120px header drawn across them, so the page title sat behind the logo.
 *
 * A page that opens with a screen height row means to go under. Anything else
 * is given the header's own height to clear, on top of the padding it already
 * had. Written as a max so a site whose header is shorter than the default
 * gains nothing it does not need. */
/* :not(.ds-has-title) because a page carrying a title band has already cleared
   the header with that band - counting the height again here left an empty
   stripe between the title and the first row. Written into this rule rather
   than as an override: the two :not(:has()) below weigh a great deal and a
   separate rule lost to them. */
.ds-header-transparent:not(.ds-has-title) .ds-main:not(:has( > * > .ds-row:first-child.ds-row-screen)):not(:has( > .ds-row:first-child.ds-row-screen)),
.ds-header-inline:not(.ds-has-title) .ds-main:not(:has( > * > .ds-row:first-child.ds-row-screen)):not(:has( > .ds-row:first-child.ds-row-screen)){
  padding-top:calc(
    var(--ds-header-h,80px)
    + var(--ds-header-pt,0px)
    + var(--ds-header-pb,0px)
    + var(--ds-main-pt,48px)
  );
}

/* Where a page has a title band, the band does the clearing.
 *
 * The band is printed above .ds-main and got no clearance of its own, so it
 * began at the very top of the page with the header drawn across it - the words
 * sat behind the logo. Meanwhile .ds-main went on adding the header's height
 * below the band, which it no longer needed, leaving an empty stripe between
 * the title and the first row.
 *
 * Both come from one place: whichever element is first on the page is the one
 * that has to clear the header, and only that one. */
.ds-has-title .ds-title{
  padding-top:calc(
    var(--ds-header-h,80px)
    + var(--ds-header-pt,0px)
    + var(--ds-header-pb,0px)
  );
}


/* ---- a post, and a page that is not built with the builder ----
   These carry the theme's own reading measure rather than the builder's full
   width grid: a paragraph is unreadable across 1200px, and a post is a column
   of prose whatever the rest of the site does. */
/* The reading width belongs to written prose, not to a built page.
   Capping .ds-page squeezed every builder page to 72 characters and centered
   it, so a two column row had no room to be two columns - the form sat in the
   middle of the screen with a third of the window empty either side. A page
   made in the builder brings its own rows, each with its own width. */
/* Written as prose, not built. The guard is the same one the page above it
   has carried all along - a built post brings its own rows, each with its own
   width, and squeezing those into a 72ch column overruled every layout choice
   made in the builder. Posts simply never got the exception pages had. */
.ds-post:not(.ds-post-built){ max-width:var(--ds-read,72ch); margin-inline:auto }
.ds-post:not(.ds-post-built) > *{ margin-block:0 1.1em }

/* A page written in the editor rather than built still reads at a sensible
   measure; one carrying a layout is left alone. */
.ds-page:not(.ds-has-layout){ max-width:var(--ds-read,72ch); margin-inline:auto }
.ds-page:not(.ds-has-layout) > *{ margin-block:0 1.1em }

.ds-post-head{ margin-bottom:2rem }
.ds-post-head h1,.ds-page-title{ margin:0 0 .4em;
  font-family:var(--ds-font-heading); font-size:var(--ds-h1-size);
  font-weight:var(--ds-h1-weight); text-transform:var(--ds-h1-case);
  color:var(--ds-heading); line-height:1.08 }

.ds-post-meta{ margin:0; font-size:14px; color:var(--ds-accent);
  letter-spacing:.04em }
.ds-post-meta a{ color:inherit }

/* Breaks the reading measure on purpose - a lead image wants the room. */
.ds-post-image{ width:100%; height:auto; margin:0 0 2rem;
  border-radius:var(--ds-field-radius,4px) }

/* The links a multi-page post prints. Left unstyled they were a run of bare
   numbers with no space between them. */
.ds-pagelinks{ display:flex; flex-wrap:wrap; gap:8px; align-items:center;
  margin:2.5rem 0 0; padding-top:1.5rem;
  border-top:1px solid var(--ds-line) }
.ds-pagelinks a,.ds-pagelinks > span{ display:inline-grid; place-items:center;
  min-width:36px; height:36px; padding:0 10px; border-radius:3px;
  border:1px solid var(--ds-line); font-size:14px; text-decoration:none }
.ds-pagelinks a:hover{ border-color:var(--ds-link-hover); color:var(--ds-link-hover) }
.ds-pagelinks > span{ background:var(--ds-line); color:var(--ds-heading) }

/* The mobile panel's own navigation landmark. */
.ds-panel-nav{ width:100%; display:flex; flex-direction:column }

/* One microwidget beside the menu. Between the links and the burger, so on a
   narrow screen it sits next to the control that replaces the menu rather than
   going with it. Sized by whatever draws it - the marks, the cart and the
   account links each carry their own settings. */
/* The space to the menu is per widget, not one figure for all four.
 *
 * This said margin-left:18px flat, so the cart, the account links, the social
 * icons and the marquee were all held off the menu by the same amount and no
 * setting could reach any of them - the number existed only here. Each kind now
 * reads its own variable and every one of those falls back to the 18 that was
 * written here, so a header nobody has touched is unchanged. */
.ds-head-widget{ flex:0 0 auto; display:flex; align-items:center }
.ds-head-widget-social{ margin-left:var(--ds-headw-social-ml, 0) }
/* No rule for the cart: its spacing is the Cart spacing card, which sets a
   margin on all four sides. A second control for the same edge was two places
   to look and one of them had no field left driving it. */
.ds-head-widget-account{ margin-left:var(--ds-headw-account-ml, 0) }
.ds-head-widget-marquee{ margin-left:var(--ds-headw-marquee-ml, 0) }
.ds-head-widget-marquee{ flex:1 1 auto; min-width:0; overflow:hidden }
.ds-head-widget .ds-microwidget-marquee{ width:100% }

.ds-brand{ flex:0 0 auto; display:flex; align-items:center; text-decoration:none;
  font-weight:600; font-family:var(--ds-font-heading) }
/* A set height, not a maximum.
   An SVG carries a ratio rather than a pixel size, so with height:auto from the
   global image rule and only a max-height here, both dimensions were auto and
   the flex parent resolved the logo to nothing - it loaded, sat in the markup,
   and drew 0x0. A raster logo survived it because it has definite pixels, which
   is why this only ever showed up with an SVG. */
/* The size set on the Branding tab, falling back to fitting the header bar.
   auto on either axis keeps the picture's own proportions, which is why the
   variable holds the keyword rather than a number the CSS has to interpret. */
.ds-brand img{
  width:var(--ds-logo-w,auto);
  height:var(--ds-logo-h,auto);
  max-width:100%; object-fit:contain;
  margin:var(--ds-logo-margin,0);
  /* Drawn once and then moved, rather than redrawn every frame.
     The header sits inside #smooth-content, so smooth scrolling translates it
     by fractional pixels - and an SVG in a fractionally transformed box is
     re-rasterized at each new subpixel offset, which makes thin strokes hop
     between pixel boundaries and read as a shake. Worst at the very top, where
     the easing settles in its smallest steps. Its own layer costs one small
     texture and removes it. */
  will-change:transform; transform:translateZ(0);
  backface-visibility:hidden }
/* Nothing set on either axis means fit the bar, the way it always did.

   Only when nothing is set. This used to apply the cap whatever the settings
   said, so a logo asked for at 125px wide came out at whatever the header
   height allowed - a size control that quietly refused the size. A figure
   typed into Branding is now the figure that is drawn, and the header grows
   to hold it. */
.ds-brand img{ height:var(--ds-logo-h, min(100%, calc(var(--ds-header-h) - 30px))) }

/* A page using the second header logo sizes it separately - it is usually a
   different file at a different weight, not the same mark recolored. */
body.ds-header-transparent .ds-brand img,
body.ds-header-alt .ds-brand img{
  margin:var(--ds-logo-alt-margin,0);
  width:var(--ds-logo-alt-w,auto);
  height:min(var(--ds-logo-alt-h,100%), calc(var(--ds-header-h) - 30px)) }

.ds-nav{ margin-left:auto }
.ds-menu-center .ds-nav{ margin-inline:auto }
.ds-menu-left .ds-nav{ margin-left:0; margin-right:auto }
.ds-nav ul{ display:flex; gap:26px; list-style:none; margin:0; padding:0 }
/* The menu's own colour, set under Menu. Blank there means inherit, which is
   the header's text colour - what the menu did before it had a colour of its
   own, so a site that never opens the setting is unchanged. */
/* The dimming comes off as soon as a link colour is chosen - a colour that was
   picked is the colour, not eighty-five percent of it. Menu - Colors sets
   --ds-menu-fade to 1 when it has an answer, and the .85 stays for a site that
   never opened that card. */
.ds-nav a{ text-decoration:none; font-size:14px;
  opacity:var(--ds-menu-fade,.85); color:var(--ds-menu-link,inherit) }
.ds-nav a:hover{ opacity:1; color:var(--ds-menu-hover,inherit) }

/* The site name, where a header has no logo image to show. */
.ds-brand{ color:var(--ds-site-name,inherit) }

/* The second set of header colors - a header sitting over a dark photograph
   needs light links where the same header over the page background does not.
 *
 * Both states, the same way the alternate logo two rules up already reads both.
 * These named only the page's own Secondary colors radio, so a transparent
 * header took the second logo and kept the first set of link colors - and the
 * two settings behind this, which say Transparent header on the tin, did
 * nothing at all unless somebody found that radio on the page as well. */
body.ds-header-transparent .ds-header .ds-nav a,
body.ds-header-alt .ds-header .ds-nav a{ color:var(--ds-head-alt-link) }
body.ds-header-transparent .ds-header .ds-nav a:hover,
body.ds-header-alt .ds-header .ds-nav a:hover{ color:var(--ds-head-alt-hover) }
body.ds-header-transparent .ds-header .ds-brand,
body.ds-header-alt .ds-header .ds-brand{ color:var(--ds-head-alt-logo) }
body.ds-header-transparent .ds-header .ds-burger i,
body.ds-header-alt .ds-header .ds-burger i{ background:var(--ds-head-alt-link) }

.ds-burger{ display:none; margin-left:auto; background:none; border:0;
  color:inherit; padding:8px; cursor:pointer }

/* ---- content ---- */
/* The gap above and below the content - between it and the title band or
   header, and between it and the footer. Set in Theme Settings, General. */
.ds-main{ padding-block:var(--ds-main-pt,48px) var(--ds-main-pb,48px) }
/* Footer.
   The colors fall back to the page rather than being set - "follow the page"
   is the common case, and a variable that is simply not written lets the
   fallback in var() do that with no extra rule. */
/* The picture moves to its own layer when it is set to zoom, because a
   background cannot be scaled without scaling everything drawn over it. The
   footer keeps its colour; the layer takes the picture. */
.ds-footer-haszoom{ position:relative; isolation:isolate }
.ds-footer-haszoom{ background-image:none }
.ds-footer-haszoom > *:not(.ds-footer-zoom){ position:relative; z-index:1 }

.ds-footer-zoom{
  position:absolute; inset:0; z-index:0; pointer-events:none;
  background-image:var(--ds-footer-img,none);
  background-size:var(--ds-footer-fit,cover);
  background-position:var(--ds-footer-pos,center);
  background-repeat:no-repeat;
  transform-origin:center;
  will-change:transform }

.ds-footer{
  background-color:var(--ds-footer-bg, var(--ds-bg));
  background-image:var(--ds-footer-img,none);
  background-size:var(--ds-footer-fit,cover);
  background-position:var(--ds-footer-pos,center);
  background-repeat:no-repeat;
  color:var(--ds-footer-text, var(--ds-text));
  padding-top:var(--ds-footer-top,56px);
  padding-bottom:var(--ds-footer-bottom,40px);
  /* The colour carries its own transparency, so there is nothing to mix it
     with - the picker writes eight digit hex. */
  border-top:var(--ds-footer-line-w,1px) solid var(--ds-footer-line, var(--ds-line));
}
.ds-footer-flat{ border-top:0 }
.ds-footer-top{ display:flex; flex-wrap:wrap; gap:40px 60px;
  align-items:flex-start; justify-content:space-between }
/* A set height, exactly as the header brand needs.
   An SVG carries a ratio rather than a pixel size, so with height:auto from the
   global image rule and only a max-width here, both dimensions were auto and
   the flex parent resolved it to nothing - the logo loaded, sat in the markup
   and drew 0x0. Worse, the collapsed link still counted as a flex child, so
   space-between shared the bar between the two remaining lines and the
   copyright drifted into the middle. */
.ds-footer-logo{ flex:0 0 auto }
.ds-footer-logo img{
  margin:var(--ds-flogo-margin,0);
  will-change:transform; transform:translateZ(0); backface-visibility:hidden;
  width:var(--ds-flogo-w,auto);
  height:var(--ds-flogo-h, var(--ds-footer-logo-h,40px));
  max-width:100%; object-fit:contain; display:block }
.ds-footer-name{ font-family:var(--ds-font-heading); font-size:20px;
  font-weight:600; text-decoration:none; color:var(--ds-heading) }

/* The blocks. Twelve columns, each block spanning what its width setting says,
   so a row of four quarters lines up with a row of two halves. The grid is a
   flex item next to the brand, hence flex:1 - it takes the space the brand
   does not want rather than being pushed onto its own line. */
.ds-fgrid{ flex:1 1 420px; min-width:0; display:grid;
  grid-template-columns:repeat(12,1fr);
  /* across only. The space below a block is a margin on the block itself, so it
     is there whether or not another row follows - a grid row gap between two
     rows of blocks leaves nothing under a single row. */
  gap:0 var(--ds-gutter,24px) }
/* The room under a heading in the footer, whichever tag it was written as.
 *
 * A footer's headings all do the same job - they title a block - whether the
 * theme writes one as an h2 or a widget writes its own h3 or h4, so one figure
 * answers for all six rather than six that would have to be kept in step.
 *
 * Each tag falls back to its own type setting, so with nothing set here every
 * heading keeps exactly the spacing it has now. */
.ds-footer h1{ margin-bottom:var(--ds-foot-head-mb, var(--ds-h1-mb, revert)) }
.ds-footer h2{ margin-bottom:var(--ds-foot-head-mb, var(--ds-h2-mb, revert)) }
.ds-footer h3{ margin-bottom:var(--ds-foot-head-mb, var(--ds-h3-mb, revert)) }
.ds-footer h4{ margin-bottom:var(--ds-foot-head-mb, var(--ds-h4-mb, revert)) }
.ds-footer h5{ margin-bottom:var(--ds-foot-head-mb, var(--ds-h5-mb, revert)) }
.ds-footer h6{ margin-bottom:var(--ds-foot-head-mb, revert) }

.ds-fblockout{ grid-column:span var(--ds-fb-span,12); min-width:0;
  margin-bottom:var(--ds-fb-gap,50px);
  /* So a block can be styled by how wide it actually is rather than by how wide
     the screen is - a quarter column is narrow on a desktop too. */
  container-type:inline-size }

/* A block told where to start on its row. Four quarters fill a row, so a fifth
   would wrap to the far left of the next one - saying it starts at three
   quarters puts it under the fourth column instead. */
.ds-fblockout[style*="--ds-fb-from"]{
  grid-column:var(--ds-fb-from) / span var(--ds-fb-span,12);
}

/* A second band of blocks sits under the first rather than beside it. The top
   of the footer is a flex row - the brand on one side and the blocks on the
   other - so a second grid would otherwise become a third column of that row.
   Full width and a forced break keeps every band a band. */
.ds-fgrid + .ds-fgrid{ flex:1 1 100%; margin-top:0 }

/* The blocks already set the distance to the bar, so the bar does not add its
   own on top. Without a blocks section above it, it still needs one. */
.ds-footer-top + .ds-footer-bar{ margin-top:var(--ds-fbar-mt, 0px) }

/* Set by the Blocks heading row in Typography, so every block heading on the
   site is one decision rather than a figure written here that no setting could
   reach. */
.ds-fb-head{ margin:0 0 12px;
  font-size:var(--ds-blockhead-size,14px);
  font-weight:var(--ds-blockhead-weight,600);
  letter-spacing:var(--ds-blockhead-track,.06em);
  line-height:var(--ds-blockhead-lh,1.3em);
  text-transform:var(--ds-blockhead-case,uppercase);
  color:var(--ds-heading) }

.ds-fb-lines{ list-style:none; margin:0; padding:0; display:grid; gap:6px;
  font-size:14px; line-height:1.6; color:var(--ds-accent) }
.ds-fb-lines a{ color:inherit }

.ds-fb-img,.ds-fb-video{ max-width:100%; height:auto; display:block; border-radius:6px }

/* The subscribe form in a footer column. A quarter of a footer is not wide
   enough for a field and a button side by side - the field came out four
   characters wide - so the button goes underneath. */
/* The field and the button on one line, as asked.
 *
 * They were stacked because a quarter of a footer is narrow and a field beside a
 * button came out too small to type in. The field can shrink now instead - it
 * takes the room the button does not - and the pair only breaks onto two lines
 * below the width where the field would be unusable. */
.ds-fb-subscribe .dsm-row{ display:flex; flex-wrap:wrap; align-items:center; gap:8px }

/* The field wins the argument over the room.
 *
 * Both were allowed to size themselves and the button - which does not shrink -
 * took 152px of a 240px column, leaving 80px to type an email address into.
 * The field is given the space and the button shrinks to its word instead. */
/* Basis zero, so the field is exactly whatever the button leaves rather than
   asking for a share that pushes the pair onto two lines and then growing to
   fill the first one on its own. */
.ds-fb-subscribe .dsm-email{ flex:1 1 0; min-width:0 }
.ds-fb-subscribe .dsm-go{ flex:0 1 auto; min-width:0; white-space:nowrap }

/* In a narrow column the button loses its wide padding rather than the field
   losing the space. A button is legible at its label; a text box is not usable
   at eighty pixels. */
@container (max-width: 340px){
  .ds-fb-subscribe .dsm-go{ padding-left:14px; padding-right:14px }
}

/* Below about 200px there is no field worth typing in beside a button at all,
   so they go back to stacking. */
@container (max-width: 200px){
  .ds-fb-subscribe .dsm-email{ flex-basis:100% }
  .ds-fb-subscribe .dsm-go{ width:100% }
}
/* Size only. The colour was the accent, which is a third answer on top of
   the footer's own text colour and the fade the plugin was applying. */
.ds-fb-subscribe .dsm-note{ font-size:13px }

/* One column on a phone. Four quarters side by side is four narrow strips.
   The block told where to start is named here too: an attribute selector
   outweighs a class, so without this a pinned block kept its quarter on a
   360px screen while everything around it went full width. */
@media (max-width:781px){
  .ds-fblockout,
  .ds-fblockout[style*="--ds-fb-from"]{ grid-column:1 / -1 }
}

.ds-footnav ul,.ds-footer-social{ display:flex; flex-wrap:wrap; gap:8px 22px;
  list-style:none; margin:0; padding:0 }
.ds-footnav ul{ flex-direction:column }
/* The marks are not styled here.
 *
 * They used to share these two rules with the footer's text links, which set
 * the accent straight onto the anchor. A mark is drawn with fill:currentColor,
 * so that colour is the mark - and it beat --ds-social-ink, which is the
 * setting on Microwidgets and Footer social. Same specificity as the rule that
 * reads the variable (0,1,1) and written later in the file, so it won every
 * time: the colour saved, reached the page as a variable on .ds-footer, and was
 * then painted over. Marks answer to --ds-social-ink alone now. */
.ds-footnav a{ text-decoration:none; font-size:14px;
  color:var(--ds-accent) }
.ds-footnav a:hover{ color:var(--ds-link-hover) }
.ds-footer-social a{ text-decoration:none; font-size:14px }

/* The logo sits on the bar with the copyright line. align-items:center so the
   mark and the text share a baseline band rather than the mark hanging above. */
/* No horizontal gap of its own. The space beside the logo is the logo's
   margin, set on Branding - a 24px gap here as well meant the two added up and
   the setting only ever moved it further out, never closer in. The row gap
   stays, for when the bar wraps onto two lines. */
.ds-footer-bar{ display:flex; flex-wrap:wrap; gap:6px 0; align-items:center;
  margin-top:var(--ds-fbar-mt, 36px); margin-bottom:var(--ds-fbar-mb, 0px);
  padding-top:var(--ds-fbar-pt, 20px); padding-bottom:var(--ds-fbar-pb, 0px) }
.ds-footer-bar .ds-fbar-end{ margin:0;
  font-size:var(--ds-fbar-size,13px);
  text-transform:var(--ds-fbar-case,none);
  color:var(--ds-fbar-text, var(--ds-accent)) }

/* Said through .ds-footer, because the footer's own link colour is written the
   same weight and later in the file - equal specificity is decided by whichever
   comes last, and the bar has to win inside itself. */
.ds-footer .ds-footer-bar a{ color:var(--ds-fbar-link, inherit) }

/* Except a social mark, which is not one of the bar's text links.
 *
 * The rule above is two classes and an element (0,2,1) and beats the one that
 * reads --ds-social-ink (0,1,1), so a mark in the bottom bar took the bar's
 * link colour - and with --ds-fbar-link unset that resolves to inherit, which
 * is the bar's own red text. The colour set under Footer social saved, was
 * emitted onto .ds-footer, and lost the cascade by one class. Said here with
 * three classes so the mark keeps its own colour wherever it is put. */
.ds-footer .ds-footer-bar .ds-footer-social a{ color:var(--ds-social-ink,currentColor) }
.ds-footer .ds-footer-bar .ds-footer-social a:hover{ color:var(--ds-social-ink-hover,var(--ds-link-hover)) }

/* With a middle, the bar is three parts rather than two.
 *
 * Auto margins split what is left over between them, which centres the middle
 * between its neighbours rather than in the bar - and moves it every time
 * either neighbour changes length. Equal outer parts instead, so the middle is
 * in the middle of the bar whatever is either side of it. */
.ds-footer-bar:has(> .ds-fbar-mid) > .ds-fbar-end{ flex:1 1 0; min-width:0 }
.ds-footer-bar:has(> .ds-fbar-mid) > .ds-fbar-mid{ flex:0 1 auto; text-align:center }
.ds-footer-bar:has(> .ds-fbar-mid) > .ds-fbar-right{ margin-left:0; justify-content:flex-end; text-align:right }

/* Logo left, copyright next to it, and the credit pushed to the far right.
   space-between was doing this by counting children, so the moment the logo
   collapsed to nothing it shared the bar between the two remaining lines and
   the copyright landed in the middle. Naming which item takes the free space
   means the layout is the same whether or not there is a logo. */
/* Only a second line of text is pushed to the far side. Applying this to the
   last child meant that with a logo and one line, that line was the last child
   and got shoved to the right edge - which is where the gap beside the logo
   came from. The left line now sits next to the mark, spaced by the logo's own
   margin and nothing else. */
.ds-footer-bar > .ds-fbar-left + .ds-fbar-right{ margin-left:auto }

/* An end lays its own items out.
 *
 * Each end holds a line of words and however many microwidgets, each in its own
 * span. As plain inline boxes they had nothing between them, so the bar read
 * "Big Wood Motorcyclescopy" - two separate items with no space, which is not a
 * spacing fault to the eye but a spelling one. A flex line with a gap, and the
 * marks sit on the same middle as the words beside them rather than dropping to
 * the text baseline. */
.ds-footer-bar .ds-fbar-end{
  display:flex; flex-wrap:wrap; align-items:center;
  gap:6px var(--ds-fbar-gap,16px);
}

/* The middle end centres its items and the last end pushes its to the right.
   Without this the items bunch at the left of an end that is itself over on the
   right, which reads as the end being in the wrong place rather than its
   contents. */
.ds-footer-bar:has(> .ds-fbar-mid) > .ds-fbar-mid{ justify-content:center }
.ds-footer-bar > .ds-fbar-right{ justify-content:flex-end }
.ds-footer-bar > .ds-fbar-left{ justify-content:flex-start }

/* The marks arrive as a list, so its bullets and indent have to go. */
.ds-footer-bar .ds-fbar-end .ds-footer-social{
  margin:0; padding:0; list-style:none;
  display:flex; align-items:center; gap:var(--ds-social-gap,10px);
}

/* What the bar does on a small screen.
 *
 * The four settings behind this - stacked or as it is, and where it aligns,
 * once for phone and once for tablet - were writing their classes onto the body
 * and no stylesheet had ever read them. Every one of them did nothing, at any
 * width, whatever it was set to.
 *
 * Said through .ds-footer as well as the body class, because an end that is
 * last or that sits beside a middle is already aligned by a rule above with
 * four classes to its name, and a rule that loses the cascade is another
 * setting that does nothing.
 *
 * Two bands that do not overlap, so the phone answer and the tablet answer are
 * never both live and there is nothing to work out about which one won. */
@media (max-width:640px){
  body.ds-fbar-hide .ds-footer .ds-footer-bar{ display:none }

  /* One under the other, each taking the full width - without the width an end
     is only as wide as its words, and aligning something inside a box the size
     of its own contents moves nothing. margin-left:auto is what pushes the
     second end to the far side on a wide screen, and it has to go for the same
     reason. */
  body.ds-fbar-stack .ds-footer .ds-footer-bar{ flex-direction:column }
  body.ds-fbar-stack .ds-footer .ds-footer-bar > .ds-fbar-end{
    width:100%; margin-left:0;
  }

  body.ds-fbar-at-left .ds-footer .ds-footer-bar > .ds-fbar-end{
    justify-content:flex-start; text-align:left;
  }
  body.ds-fbar-at-center .ds-footer .ds-footer-bar > .ds-fbar-end{
    justify-content:center; text-align:center;
  }
  body.ds-fbar-at-right .ds-footer .ds-footer-bar > .ds-fbar-end{
    justify-content:flex-end; text-align:right;
  }
}

@media (min-width:641px) and (max-width:1024px){
  body.ds-fbart-hide .ds-footer .ds-footer-bar{ display:none }

  body.ds-fbart-stack .ds-footer .ds-footer-bar{ flex-direction:column }
  body.ds-fbart-stack .ds-footer .ds-footer-bar > .ds-fbar-end{
    width:100%; margin-left:0;
  }

  body.ds-fbart-at-left .ds-footer .ds-footer-bar > .ds-fbar-end{
    justify-content:flex-start; text-align:left;
  }
  body.ds-fbart-at-center .ds-footer .ds-footer-bar > .ds-fbar-end{
    justify-content:center; text-align:center;
  }
  body.ds-fbart-at-right .ds-footer .ds-footer-bar > .ds-fbar-end{
    justify-content:flex-end; text-align:right;
  }
}

/* Underlined only where the bar is set to.
 *
 * The switch adds the underline, so something has to be taking it away first -
 * every other link in the footer is reset where it is styled, and the bar's own
 * links are typed in by hand and were never covered by any of them. So they
 * kept the browser's default and the box read as though it did nothing.
 *
 * The offset keeps the rule off the letterforms at this size. */
.ds-footer-bar a{ text-decoration:none }

.ds-fbar-underline .ds-footer-bar a{
  text-decoration:underline; text-underline-offset:3px;
  text-decoration-thickness:from-font }

/* And it comes off on hover.
   An underline that is there in both states is not telling anybody the link
   is being pointed at - the rule going is the answer to the rule being the
   resting state. */
.ds-fbar-underline .ds-footer-bar a:hover,
.ds-fbar-underline .ds-footer-bar a:focus-visible{ text-decoration:none }

@media (max-width:640px){
  .ds-footer-top{ gap:28px }
  .ds-footer-bar{ margin-top:26px }

}

.ds-404{ padding-block:80px; text-align:center }
/* An icon draws in the text colour around it unless the Elements tab has been
   given one - so an icon inside a button, a heading or a paragraph still takes
   that colour, which is what makes it read as part of the words. */
.ds-icon{ display:inline-block; vertical-align:middle; color:var(--ds-icon-ink, inherit) }

/* Except on a button, where it takes the button's own label colour.
 *
 * The note above says an icon inside a button reads as part of the words, and
 * that is the intent - but --ds-icon-ink is a colour chosen for icons sitting
 * on the page, and a button carries a fill of its own. A site with a lime icon
 * colour and a lime button drew a lime arrow on lime, which is an arrow nobody
 * can see. currentColor is whatever the label is, whatever the button does. */
.ds-btn .ds-icon,
.ds-btn .ds-btn-ico,
.wp-block-button__link .ds-icon{ color:currentColor }

/* Centred by ink, not by boxes.
 *
 * The icons are drawn on a 24 grid with the artwork spanning 3 to 21, so every
 * icon box carries three units of nothing down each side - 2px at button size.
 * The label has no such margin: its ink starts where its box starts. So a
 * button with equal padding measures centred and looks pushed right, because
 * the eye sees 23px of space on the left and 20px on the right. Measured on
 * the hero pair: 22.96 against 20.32.
 *
 * Pulling the icon left by its own inset shifts the whole centred group by
 * half of it, which is exactly the bias - the flex line gets narrower by the
 * inset, so centring gives half of it back and the group lands one and a bit
 * pixels to the left. The icon keeps its size and its gap to the words.
 *
 * A figure rather than a guess: 3/24 of 1.15em is .144em. An icon set drawn
 * tight to its box sets this to zero. */
.ds-btn > .ds-icon:first-child,
.ds-btn > .ds-btn-ico:first-child{ margin-inline-start:calc(var(--ds-btnicon-inset, .144em) * -1) }

.ds-btn > .ds-icon:last-child,
.ds-btn > .ds-btn-ico:last-child{ margin-inline-end:calc(var(--ds-btnicon-inset, .144em) * -1) }

/* An icon with no words either side of it is the whole content, and shifting
   it would push it off its own centre. */
.ds-btn > .ds-icon:only-child,
.ds-btn > .ds-btn-ico:only-child{ margin-inline:0 }



/* ============================================================
   HEADER, MENU AND FOOTER
   ============================================================ */

/* Page width lines up with the content; full goes edge to edge. The shell is
   what carries the measure, so widening the header means taking the cap off
   rather than keeping a second set of measurements in step. */
.ds-headw-full .ds-header > .ds-shell{ max-width:none }
.ds-footw-full .ds-footer > .ds-shell{ max-width:none }

/* Header background. Transparent is the default and paints nothing. */
.ds-headbg-color .ds-header{ background:var(--ds-header-bg, var(--ds-bg)) }
.ds-headbg-image .ds-header{
  background-image:var(--ds-header-img);
  background-size:var(--ds-header-fit, cover);
  background-position:center;
  background-repeat:no-repeat;
}

/* ---- the menu ---- */
.ds-nav ul{ display:flex; gap:var(--ds-menu-gap,26px); list-style:none; margin:0; padding:0 }
.ds-nav a{
  display:inline-block; padding:var(--ds-menu-pad,8px 2px);
  margin:var(--ds-menu-margin,0);
  font-family:var(--ds-menu-font, var(--ds-font-heading));
  font-size:var(--ds-menu-size,14px); font-weight:var(--ds-menu-weight,500);
  text-transform:var(--ds-menu-case,none);
  text-decoration:none; position:relative;
}
.ds-menu-right  .ds-nav{ margin-left:auto }
.ds-menu-center .ds-nav{ margin-inline:auto }
.ds-menu-left   .ds-nav{ margin-left:0; margin-right:auto }

/* An underline drawn from the left rather than text-decoration: it can be
   animated, and it never shifts the line it sits under. */
.ds-mhover-underline .ds-nav a::after{
  content:""; position:absolute; left:0; right:0; bottom:2px; height:1px;
  background:currentColor; transform:scaleX(0); transform-origin:left;
  transition:transform .3s cubic-bezier(.7,0,.3,1);
}
.ds-mhover-underline .ds-nav a:hover::after,
.ds-mhover-underline .ds-nav a:focus-visible::after{ transform:scaleX(1) }

/* The label slides up to an identical copy of itself, taken from a data
   attribute - so nothing is duplicated in the markup. */
/* The clip is .ds-mclip, which wraps the label and nothing else. Clipping on
   the anchor instead only works while the anchor is exactly one line tall, and
   it is not: a parent adds a chevron, and every item adds padding. */
.ds-mhover-slide .ds-nav a{ display:inline-flex; align-items:center }
.ds-mhover-slide .ds-nav .ds-mclip{ display:inline-block; overflow:hidden;
  vertical-align:bottom }
.ds-mhover-slide .ds-nav .ds-mclip .ds-mlabel{ display:block; position:relative;
  transition:transform .34s cubic-bezier(.7,0,.3,1) }
/* The copy has to lay out exactly like the label it replaces.

   It was nowrap and had no width, so an absolutely positioned box shrank to
   fit its one long line. On a top level item that is the same shape as the
   label and nobody noticed; on a dropdown item narrow enough to wrap, the
   label sat on two lines and the copy arrived on one - inside a clip the
   height of the label and the width of its widest line, so hovering "Cursor
   image preview" replaced it with "Cursor image prev" cut off mid word.

   width:100% is the label's own width, which is where the label wrapped - so
   the copy breaks in the same places and stands exactly as tall. That is also
   what makes the slide land: top:100% and translateY(-100%) only meet when
   the two boxes are the same height. It does the nowrap's job too, because a
   label that fits on one line has a width that fits it on one line. */
.ds-mhover-slide .ds-nav .ds-mclip .ds-mlabel::after{
  content:attr(data-text); position:absolute; left:0; top:100%; width:100%;
}
.ds-mhover-slide .ds-nav a:hover .ds-mclip .ds-mlabel,
.ds-mhover-slide .ds-nav a:focus-visible .ds-mclip .ds-mlabel{ transform:translateY(-100%) }

/* Scramble and tickerboard replace the characters, so the width would jump as
   letters change. Tabular figures and a reserved width stop the menu shuffling
   while one item animates. */
.ds-mhover-scramble .ds-nav a,
.ds-mhover-ticker   .ds-nav a{ font-variant-numeric:tabular-nums }
.ds-mhover-scramble .ds-nav a .ds-mlabel,
.ds-mhover-ticker   .ds-nav a .ds-mlabel{ display:inline-block; min-width:var(--ds-mw,auto) }

/* ---- submenus ---- */
.ds-nav li{ position:relative }
.ds-nav .sub-menu{
  position:absolute; top:100%; left:0; z-index:60;
  display:flex; flex-direction:column; padding:var(--ds-submenu-inset,8px) 0;
  min-width:var(--ds-submenu-w,190px);
  width:var(--ds-submenu-w,auto);
  background:var(--ds-header-bg, var(--ds-bg));
  border:1px solid var(--ds-line);
  opacity:0; visibility:hidden; pointer-events:none;
}
/* The gap on .ds-nav ul spaces top-level items across the header. A submenu is
   a ul too, so it was picking that up and adding it to the link padding - which
   is how a dropdown ends up with an inch between its items. Spacing inside a
   dropdown is the padding, and only the padding. */
.ds-nav .sub-menu{ gap:0 }

/* ---- the dropdown's own colours ----
   Every one falls back to the header, so a site that never opens the Submenu
   section gets a dropdown that matches the menu it came from. */
.ds-nav .sub-menu{ background:var(--ds-sub-bg, var(--ds-header-bg, var(--ds-bg)));
  border-color:var(--ds-sub-border-color, var(--ds-line)) }
.ds-nav .sub-menu a{ color:var(--ds-sub-text, inherit) }
.ds-nav .sub-menu a:hover,
.ds-nav .sub-menu a:focus-visible{
  background:var(--ds-sub-bg-hover, transparent);
  color:var(--ds-sub-text-hover, var(--ds-link-hover, inherit)) }

/* A line between one item and the next.
   li + li, so it is only ever drawn between two items - never above the first
   or below the last, where the panel's own border already is.

   An inset shadow rather than a border, so it costs no layout: a border here
   would move every link down by a pixel the moment the line was switched on.
   The opacity is mixed into the colour rather than set on the link, which would
   have faded the text along with the line. Nothing is written unless the line
   is switched on, so --ds-sub-div is undefined and this falls to transparent. */
.ds-nav .sub-menu li + li > a{
  box-shadow:inset 0 1px 0 0
    color-mix(in srgb,
      var(--ds-sub-div, transparent) calc(var(--ds-sub-div-op, 1) * 100%),
      transparent) }
.ds-nav .sub-menu a{ padding:var(--ds-submenu-pad,8px 16px); width:100%;
  display:block; line-height:1.3 }
.ds-nav li:hover > .sub-menu,
.ds-nav li:focus-within > .sub-menu{ opacity:1; visibility:visible; pointer-events:auto }

/* A second level flies out to the side rather than dropping again - a dropdown
   under a dropdown covers the item that opened it. The parent li has to be
   positioned for that, which it is not at the top level. */
/* A right-aligned menu opens its dropdowns from their right edge. Opening from
   the left pushed the last one past the window and gave the whole page a
   horizontal scrollbar - on every page, not just this one. */
/* Left edge to left edge, like every other dropdown. Pinning the panel's right
   edge to the parent's made it open leftward, so it read as sitting to the
   right of the link it belonged to. menu.js measures the room and adds
   .ds-room where a panel would run past the window, which is what handles the
   last item in a right aligned menu rather than pinning them all. */
.ds-menu-right .ds-nav > ul > li > .sub-menu{ left:0; right:auto }
.ds-menu-right .ds-nav > ul > li.ds-flip > .sub-menu{ left:auto; right:0 }

/* And nothing a menu does should be able to widen the page. clip rather than
   hidden, so it does not become a scroll container. */
.ds-theme{ overflow-x:clip }

.ds-nav .sub-menu li{ position:relative }
/* Above the list it opens from, or it lands on top of those links and every
   click goes to whatever is underneath it instead. */
/* Pulled up by the container's own top padding, so the first item of the
   flyout sits on the same line as the item that opened it. Without this it
   starts a padding's worth lower and looks misaligned however the link
   paddings are set. */
/* Pulled up by the panel's own top padding, not by the submenu inset.
   Those are two different numbers: the inset is the gap between a dropdown and
   the bar above it, and using it here happened to be close but left the first
   flyout item sitting a few pixels above the item that opened it, which is
   exactly the misalignment. The panel's padding is what has to be cancelled,
   so the first link lines up with its parent whatever either value is set to. */
/* Zero, and nothing to compensate for. The flyout is positioned against the
   list item it opens from, and that item already starts inside the panel's
   padding - so the first link lines up with its parent on its own.
   Three attempts to correct an offset here all failed because a second copy of
   this selector further down the file was setting top to the submenu inset,
   and being later with the same specificity it won every time. The duplicate
   is gone; the offset it was correcting for never existed.
   The one pixel that remains is the panel's own top border: the parent panel's
   border pushes its links down by it, and a flyout pinned to the list item does
   not inherit that. Written as the border width rather than a literal 1, so it
   follows if the border ever changes. */
/* The two panels share a top edge.
   Aligning the flyout's first link with the link that opens it is the usual
   rule, and it is what this did - but the panel it sits in then starts lower
   than the panel it came from by that panel's own padding and border, which is
   what reads as crooked. Pulled up by exactly those two, so the boxes line up.
   Asked three times; measuring the links said 0.57px and looked fine, because
   the links were never what was out. */
/* Measured this time, in the browser, instead of reasoned about.
 *
 * The flyout is positioned against the li it belongs to. At top:1px its border
 * sits 1px under the li's top edge, and its own border and padding then push its
 * first link down by both again before anything is drawn - while the parent link
 * starts at the li's top edge with nothing in front of it.
 *
 * Both complaints are that one quantity. The panels were 11.5px apart and the
 * links were 11.5px apart, because the same border and padding move the box and
 * the first line together - which is why fixing one never fixed the other and
 * this came back twice.
 *
 * Pulled up by exactly those two. The panels then share a top edge AND the
 * flyout's first item sits on the line of the item it came from. Written as the
 * variables rather than a figure, so changing the panel padding cannot put it
 * out again. */
.ds-nav .sub-menu .sub-menu{
  top:calc(-1 * (var(--ds-sub-border,1px) + var(--ds-submenu-inset,8px)));
  left:100%; margin-left:-1px; z-index:70 }

/* A right-aligned menu has its dropdowns against the window edge, so there is
   never room to the right - the flyout opens left by default there and only
   goes right when menu.js measures room for it. */
.ds-menu-right .ds-nav .sub-menu .sub-menu{ left:auto; right:100%; margin:0 -1px 0 0 }
.ds-menu-right .ds-nav .sub-menu li.ds-room > .sub-menu{ left:100%; right:auto; margin:0 0 0 -1px }

/* It opens to the right. A flipped one is measured by menu.js and only happens
   when it genuinely will not fit - and it is offset by its own width from the
   parent's left edge rather than by right:100%, which resolved against the
   whole submenu and dropped the flyout across the list it came from. */
.ds-nav .sub-menu li.ds-flip > .sub-menu{ left:auto; right:100%; margin:0 -1px 0 0;
  z-index:70 }

/* No chevron drawn here. The markup already carries a .ds-chev on any item with
   children, styled further down - adding a second one with :has() gave every
   submenu parent two of them. It is turned to point sideways instead, because
   at this level the submenu opens sideways. */
.ds-nav .sub-menu .menu-item-has-children > a{ display:flex; align-items:center; gap:10px }
.ds-nav .sub-menu .menu-item-has-children > a .ds-chev{
  margin-left:auto; transform:rotate(-45deg) }
.ds-nav .sub-menu .menu-item-has-children:hover > a .ds-chev{ transform:rotate(-45deg) translateX(1px) }
.ds-nav .sub-menu .menu-item-has-children.ds-flip > a .ds-chev{ transform:rotate(135deg) }

.ds-sub-fade-down .ds-nav .sub-menu{ transform:translateY(-6px);
  transition:opacity .22s ease, transform .22s ease, visibility .22s }
.ds-sub-fade-down .ds-nav li:hover > .sub-menu,
.ds-sub-fade-down .ds-nav li:focus-within > .sub-menu{ transform:translateY(0) }
.ds-sub-fade .ds-nav .sub-menu{ transition:opacity .22s ease, visibility .22s }
.ds-sub-none .ds-nav .sub-menu{ transition:none }

/* the chevron, added only where there is actually a submenu */
.ds-nav .menu-item-has-children > a .ds-chev{
  display:inline-block;
  /* Set on the Menu tab. The same value drives the mark on the phone panel, so
     one chevron is one size wherever it appears. */
  width:var(--ds-chev,7px); height:var(--ds-chev,7px); margin-left:7px;
  border-right:1.5px solid currentColor; border-bottom:1.5px solid currentColor;
  transform:translateY(-2px) rotate(45deg); transition:transform .2s ease;
}
.ds-nav .menu-item-has-children:hover > a .ds-chev{ transform:translateY(1px) rotate(-135deg) }

/* ---- the hamburger ---- */
.ds-burger{
  display:none; cursor:pointer; color:inherit; width:auto;
  /* The gap scales with the mark, or only its width would.
     Five against a width of 24, which is what it was drawn at - so the whole
     icon keeps its 3:2 shape at any size instead of turning square when it is
     made small and flat when it is made large. */
  flex-direction:column; justify-content:center;
  gap:calc(var(--ds-burger-size,24px) / 4.8);
  padding:var(--ds-burger-pad,8px);

  /* The box. These come last in the block on purpose - an earlier version put
     them first and the rule's own background:none and margin-left:auto, three
     lines below, quietly won. */
  background:var(--ds-burger-bg,transparent);
  border:var(--ds-burger-border,0) solid var(--ds-burger-edge,transparent);
  border-radius:var(--ds-burger-radius,0);
  /* The left value is decided in PHP: auto while it is zero, so the burger
     stays pushed to the end of the header, and the typed value once there is
     one. calc() cannot mix auto with a length, so the choice has to be made
     before the CSS is written. */
  margin:var(--ds-burger-margin, 0 0 0 auto);
  transition:background .28s ease, border-color .28s ease;
}
/* One figure for the whole mark.

   The bar's thickness and the space between the three are worked out from
   the width rather than set beside it, so making the burger bigger makes a
   bigger burger instead of three long thin lines. The proportions are the
   ones it was drawn at: 24 wide, 2 thick, 5 apart. */
.ds-burger i{ display:block;
  width:var(--ds-burger-size,24px);
  /* A twelfth of the width, which is the 2px it was drawn at against 24.
     The floor is 1px rather than 2: at 2 a small burger kept full thickness
     while its width shrank, so the three bars closed up and the mark came out
     square instead of the 3:2 it is at every other size. */
  height:max(1px, calc(var(--ds-burger-size,24px) / 12));
  background:var(--ds-burger-ink, currentColor);
  transition:transform .3s cubic-bezier(.7,0,.3,1), opacity .2s ease,
             width .3s ease, background .28s ease }

/* Every animation except the fill changes the color by cross-fading the bar
   itself. The fill has its own layer below, because a sweep needs a direction
   and a background transition has none. */
.ds-burger:hover i,.ds-burger:focus-visible i{
  background:var(--ds-burger-ink-hover, var(--ds-burger-ink, currentColor)) }
.ds-bhov-fill .ds-burger:hover i,.ds-bhov-fill .ds-burger:focus-visible i{
  background:var(--ds-burger-ink, currentColor) }
/* The four other marks, as fractions of the size rather than as the figures
   they happened to be drawn at against a width of 24 - 16, 14, 5 and 15. Left
   as pixels they kept their old length while the full-width bars beside them
   grew or shrank, so a short bar became the long one and every style but Lines
   came apart the moment the size was changed. */
.ds-burger-minimal i:nth-child(2){ display:none }
.ds-burger-minimal i:nth-child(3){ width:calc(var(--ds-burger-size,24px) * 2 / 3) }
.ds-burger-plus i:nth-child(2){ width:calc(var(--ds-burger-size,24px) * 7 / 12) }
.ds-burger-dots i{
  width:calc(var(--ds-burger-size,24px) / 4.8);
  height:calc(var(--ds-burger-size,24px) / 4.8);
  border-radius:50%; margin-inline:auto }
/* Three bars stepping in. Distinct from the other five at a glance, and
   built from the same three bars, so it needs nothing of the markup. */
.ds-burger-steps i:nth-child(2){ width:calc(var(--ds-burger-size,24px) * 3 / 4) }
.ds-burger-steps i:nth-child(3){ width:calc(var(--ds-burger-size,24px) / 2) }
.ds-burger-arrow i:nth-child(1){ width:calc(var(--ds-burger-size,24px) * 5 / 8);
  transform:rotate(45deg) translate(calc(var(--ds-burger-size,24px) / 8), calc(var(--ds-burger-size,24px) / 8)) }
.ds-burger-arrow i:nth-child(3){ width:calc(var(--ds-burger-size,24px) * 5 / 8);
  transform:rotate(-45deg) translate(calc(var(--ds-burger-size,24px) / 8), calc(var(--ds-burger-size,24px) / -8)) }

/* Open, every style becomes a cross. One shape means close, whatever it looked
   like closed. */
/* What the burger does under the cursor.
   The fill is a second layer inside each bar rather than a background change,
   so it can be drawn from one end - a color transition has no direction. */
/* The close icon's own colour, while the menu is open. Blank falls all the way
   back to the burger's, so the two are one colour until somebody says they are
   not - which they usually are not, since one sits on the header and the other
   over the overlay. */
/* The header, over the panel, while the panel is open.
 *
 * The burger is the close icon - it turns into one and stays where it was - but
 * the header it lives in is a stacking context at 50 and the panel is at 80, so
 * the whole thing was behind the overlay. Nothing at those coordinates but the
 * menu list: no close icon to see and nothing to click.
 *
 * Raised as the header rather than as the burger, because a child cannot climb
 * out of its parent's context. Its own background and border go while it is up
 * there, or a solid band would sit across the top of the overlay. */
/* Under the panel, and out of its way. The z-index here used to be 81,
   one above the panel, so the burger could serve as the close - see the
   rule further down that sets the same thing. Both say 70 now. */
body.ds-menu-open .ds-header{
  z-index:70; background:transparent; border-bottom-color:transparent }

/* Nothing for it to do while the panel is open, and a burger left on
   screen recolouring itself into a cross reads as a second close button
   in the wrong corner. Opacity, not visibility - menu.js hands focus
   back to it on the way out. */
body.ds-menu-open .ds-burger{
  opacity:0; pointer-events:none;
  transition:opacity var(--ds-panel-time,.38s) ease }

body.ds-menu-open .ds-burger i{
  background:var(--ds-menuclose-ink, var(--ds-burger-ink, currentColor)) }
body.ds-menu-open .ds-burger:hover i,
body.ds-menu-open .ds-burger:focus-visible i{
  background:var(--ds-menuclose-ink-hover,
    var(--ds-menuclose-ink, var(--ds-burger-ink-hover, var(--ds-burger-ink, currentColor)))) }
body.ds-menu-open .ds-burger i::after{
  background:var(--ds-menuclose-ink-hover,
    var(--ds-burger-ink-hover, var(--ds-accent,#fff))) }
/* The word close, when that is the chosen shape. */
body.ds-menu-open .ds-menuclose-word .ds-burger::after{
  color:var(--ds-menuclose-ink, var(--ds-burger-ink, currentColor)) }

.ds-burger i{ position:relative; overflow:hidden }
.ds-burger i::after{ content:''; position:absolute; inset:0;
  background:var(--ds-burger-ink-hover, var(--ds-accent,#fff));
  transform:scaleX(0); transform-origin:0 50%;
  transition:transform .32s cubic-bezier(.22,1,.36,1) }

.ds-bhov-fill .ds-burger:hover i::after,
.ds-bhov-fill .ds-burger:focus-visible i::after{ transform:scaleX(1) }
.ds-bhov-fill .ds-burger:hover i:nth-child(2)::after{ transition-delay:.06s }
.ds-bhov-fill .ds-burger:hover i:nth-child(3)::after{ transition-delay:.12s }

.ds-bhov-stagger .ds-burger:hover i:nth-child(1){ width:16px }
.ds-bhov-stagger .ds-burger:hover i:nth-child(2){ width:20px; transition-delay:.05s }
.ds-bhov-stagger .ds-burger:hover i:nth-child(3){ width:12px; transition-delay:.1s }

.ds-bhov-spread .ds-burger:hover i:nth-child(1){ transform:translateY(-3px) }
.ds-bhov-spread .ds-burger:hover i:nth-child(3){ transform:translateY(3px) }

.ds-bhov-nudge .ds-burger:hover i:nth-child(1){ transform:translateX(4px) }
.ds-bhov-nudge .ds-burger:hover i:nth-child(2){ transform:translateX(7px); transition-delay:.04s }
.ds-bhov-nudge .ds-burger:hover i:nth-child(3){ transform:translateX(4px); transition-delay:.08s }

/* Never while the panel is open - the icon is a close button by then, and a
   hover state pulling it back toward a hamburger reads as broken. */
.ds-burger[aria-expanded="true"] i::after{ transform:scaleX(0) !important }

/* The burger IS the close icon, so the header it sits in has to be above the
   panel while the panel is open.

   The panel is fixed at z-index 80. A sticky header carries 81 and a
   transparent one is positioned, so both stayed on top - but a plain inline
   header is static, z-index does nothing to it, and the panel painted straight
   over the only way out of the menu. Nothing was missing from the markup; the
   close icon was underneath.

   Each header mode gets its own position back on the line below, so raising it
   cannot turn a sticky header relative for as long as the menu is open. */
/* What of the header is left showing over the open panel.
 *
 * The panel is the menu and nothing else; the logo and the microwidgets above
 * it are the header, lifted over the panel by the rule below so its close
 * button can be reached. That is worth keeping on a shop, where somebody
 * opening the menu may be on the way to the basket, and not worth it on a site
 * whose menu should be the only thing on the screen.
 *
 * The burger is never hidden by any of these - it is the close button, and a
 * panel that cannot be closed is not a setting anybody wants. */
body.ds-panel-show-logo.ds-menu-open .ds-head-widget{ display:none }
/* Nothing of the header over an open panel, whichever way the logo is set:
   with none there is no logo at all, and with the menu logo the panel draws
   its own - so the header would be a second one beside it. */
body.ds-panel-show-none.ds-menu-open .ds-head-widget,
body.ds-panel-show-none.ds-menu-open .ds-brand,
body.ds-panel-show-none.ds-menu-open .ds-nav,
body.ds-panel-show-mobile.ds-menu-open .ds-head-widget,
body.ds-panel-show-mobile.ds-menu-open .ds-brand,
body.ds-panel-show-mobile.ds-menu-open .ds-nav{ display:none }

/* The top bar goes while the panel is open.
 *
 * The panel covers the screen, so the bar above it is a strip of the page
 * showing over a full screen overlay - and because the header is lifted over
 * the panel with the bar still above it in the flow, the logo row is pushed
 * down by the bar's height. That is the band of empty screen above the logo on
 * a tablet: on a phone the bar is set to Hidden anyway, so it only shows at the
 * width where the bar is still on and the menu is already the burger.
 *
 * No width in the rule. The menu can only be open where the burger exists, so
 * every screen this can happen on is one where it should. The height goes with
 * it, for the same reason a hidden bar zeroes it at the breakpoints. */
body.ds-menu-open .ds-bar{ display:none }
body.ds-menu-open{ --ds-bar-h:0px }

/* Under the panel, not over it. The header was raised above the overlay
   so its burger could double as the close; the panel has its own now, and
   a header left on top drags its background - blur included - across the
   open menu. Positioned, so it still sits above the page it belongs to. */
body.ds-menu-open .ds-header{ position:relative; z-index:70 }
body.ds-header-sticky.ds-menu-open .ds-header{ position:sticky }
body.ds-header-transparent.ds-menu-open .ds-header{ position:absolute }

.ds-burger:hover{
  background:var(--ds-burger-bg-hover, var(--ds-burger-bg,transparent));
  border-color:var(--ds-burger-edge-hover, var(--ds-burger-edge,transparent)) }

@media (prefers-reduced-motion: reduce){
  .ds-burger,.ds-burger i,.ds-burger i::after{ transition:none }
}

/* What the burger becomes while the panel is open.
   Every one of these works from the same three bars, so the change is a
   transform rather than a swap - the icon moves into its new shape instead of
   one icon disappearing and another appearing in its place.

   This is the MENU's close icon. The lightbox has its own, set separately and
   drawn as an SVG - see .ds-lb-close-* - and neither is meant to follow the
   other. The prefix says menu because ds-close-* read as though it were the one
   close icon for the whole theme.

   The cross is the shape people actually pick, so it is the one worth having
   more than one of: two weights and two sizes. The chevron that used to sit
   beside it was the same three bars at half length, which reads as a smaller
   cross rather than as a chevron - the picker was showing one icon twice. */
/* The bars swing into a cross at whatever size the close mark is set to, and
   meet in the middle: the distance each travels is a quarter of that size,
   which is where the outer two bars sit when three are stacked. Written from
   the variable rather than as 24 and 7, so changing the size still gives a
   cross rather than two crossed lines missing each other. */
.ds-menuclose-morph .ds-burger[aria-expanded="true"] i:nth-child(1){
  width:var(--ds-menuclose-size,24px);
  transform:translateY(calc(var(--ds-menuclose-size,24px) / 3.43)) rotate(45deg) }
.ds-menuclose-morph .ds-burger[aria-expanded="true"] i:nth-child(2){ opacity:0 }
.ds-menuclose-morph .ds-burger[aria-expanded="true"] i:nth-child(3){
  width:var(--ds-menuclose-size,24px);
  transform:translateY(calc(var(--ds-menuclose-size,24px) / -3.43)) rotate(-45deg) }

/* The four crosses. Shared geometry first, then only what differs: how long the
   two bars are, and how thick. Written this way so a fifth is one line, and so
   the four provably differ by nothing else. */
.ds-menuclose-cross-light .ds-burger[aria-expanded="true"],
.ds-menuclose-cross-bold  .ds-burger[aria-expanded="true"],
.ds-menuclose-cross-large .ds-burger[aria-expanded="true"],
.ds-menuclose-cross-small .ds-burger[aria-expanded="true"]{ transform:rotate(90deg) }

.ds-menuclose-cross-light .ds-burger[aria-expanded="true"] i:nth-child(2),
.ds-menuclose-cross-bold  .ds-burger[aria-expanded="true"] i:nth-child(2),
.ds-menuclose-cross-large .ds-burger[aria-expanded="true"] i:nth-child(2),
.ds-menuclose-cross-small .ds-burger[aria-expanded="true"] i:nth-child(2){ opacity:0 }

.ds-menuclose-cross-light .ds-burger[aria-expanded="true"] i:nth-child(1),
.ds-menuclose-cross-bold  .ds-burger[aria-expanded="true"] i:nth-child(1),
.ds-menuclose-cross-large .ds-burger[aria-expanded="true"] i:nth-child(1),
.ds-menuclose-cross-small .ds-burger[aria-expanded="true"] i:nth-child(1){
  width:var(--ds-x-len,22px); height:var(--ds-x-bar,2px);
  transform:translateY(7px) rotate(45deg) }

.ds-menuclose-cross-light .ds-burger[aria-expanded="true"] i:nth-child(3),
.ds-menuclose-cross-bold  .ds-burger[aria-expanded="true"] i:nth-child(3),
.ds-menuclose-cross-large .ds-burger[aria-expanded="true"] i:nth-child(3),
.ds-menuclose-cross-small .ds-burger[aria-expanded="true"] i:nth-child(3){
  width:var(--ds-x-len,22px); height:var(--ds-x-bar,2px);
  transform:translateY(-7px) rotate(-45deg) }

.ds-menuclose-cross-light .ds-burger[aria-expanded="true"]{ --ds-x-len:22px; --ds-x-bar:1px }
.ds-menuclose-cross-bold  .ds-burger[aria-expanded="true"]{ --ds-x-len:22px; --ds-x-bar:3px }
.ds-menuclose-cross-large .ds-burger[aria-expanded="true"]{ --ds-x-len:30px; --ds-x-bar:2px }
.ds-menuclose-cross-small .ds-burger[aria-expanded="true"]{ --ds-x-len:15px; --ds-x-bar:2px }

.ds-menuclose-minus .ds-burger[aria-expanded="true"] i:nth-child(1){ opacity:0 }
.ds-menuclose-minus .ds-burger[aria-expanded="true"] i:nth-child(2){ width:24px }
.ds-menuclose-minus .ds-burger[aria-expanded="true"] i:nth-child(3){ opacity:0 }

/* The word instead of a shape. The label is drawn by CSS, so the button keeps
   its own accessible name and nothing has to be swapped in the markup. The word
   itself is a setting - it was hard coded to Close, so a site that wanted Back
   or Menu had no way to say so. */
.ds-menuclose-word .ds-burger[aria-expanded="true"] i{ opacity:0 }
.ds-menuclose-word .ds-burger[aria-expanded="true"]{ width:auto }
.ds-menuclose-word .ds-burger[aria-expanded="true"]::after{
  content:var(--ds-menuclose-word,'Close'); position:absolute; inset:0;
  display:grid; place-items:center;
  /* Whatever case was typed. Forcing uppercase meant a field where "Close"
     and "close" drew the same thing and lowercase was unreachable. */
  font-size:13px; letter-spacing:.08em }
.ds-menuclose-word .ds-burger{ position:relative }

/* ---- the mobile panel ---- */
.ds-panel{
  position:fixed; inset:0; z-index:80;
  /* Panel padding. It used to be handed to margin while the field said
     padding, so the gap above the logo answered to nothing. */
  margin:0;
  background-color:var(--ds-panel-bg, var(--ds-bg));
  display:flex; flex-direction:column; justify-content:center;
  /* Four, not a shorthand: a shorthand means typing one side wipes the
     other three, and the gutter is one of them. */
  padding:var(--ds-panel-pt, 40px) var(--ds-panel-pr, var(--ds-gutter,24px))
          var(--ds-panel-pb, 40px) var(--ds-panel-pl, var(--ds-gutter,24px));
  visibility:hidden;
  transition:opacity var(--ds-panel-time,.38s) cubic-bezier(.7,0,.3,1),
             transform var(--ds-panel-time,.38s) cubic-bezier(.7,0,.3,1),
             visibility var(--ds-panel-time,.38s);
}
.ds-panel-nav ul{ display:flex; flex-direction:column; gap:var(--ds-panel-gap,18px);
  list-style:none; margin:0; padding:0 }
/* Where the links sit down the panel, and pushed to the top the moment
   they are taller than it. Menu position writes the two margins:
   auto both ends is the middle, one auto is the other end. */
.ds-panel > .ds-panel-nav > ul{ margin-block:var(--ds-panel-links-y, auto) }

/* A menu longer than the screen scrolls inside the panel rather than being cut
   off at the bottom of it. The bar is its own thin one - the site's scrollbar
   settings are for the page, and this is a panel over the top of it.
   overscroll-behavior stops the page underneath moving once this hits its end. */
/* The scroller is the full height of the overlay, not the height of the list.
 *
 * A centred list is as tall as its items, so the bar it carried was a short
 * stub floating in the middle of the screen beside the links. Filling the panel
 * puts the bar down the edge of the overlay where anybody would look for it,
 * and the list is centred inside it with auto margins - justify-content would
 * centre it too, but a centred flex item that outgrows its box has its top cut
 * off and cannot be scrolled back to. */
.ds-panel > .ds-panel-nav,
.ds-panel > ul{
  flex:1 1 auto; width:100%; display:flex; flex-direction:column;
  max-height:100%; overflow-y:auto; overscroll-behavior:contain;
  /* scrollbar-color is inherited, and the site's own scrollbar setting puts one
     on the root - which is enough to make Chrome ignore every ::-webkit rule
     below and draw its full width bar. Handing this scroller back to auto is
     what lets the five pixels underneath apply. */
  /* No bar at all, on either engine. A menu that scrolls when it has to is
     useful; a bar drawn down the side of an overlay is a piece of browser
     furniture sitting on top of a design. The wheel, a drag and the keyboard
     all still work - only the drawing of it is gone. */
  scrollbar-width:none }

.ds-panel > .ds-panel-nav::-webkit-scrollbar,
.ds-panel > ul::-webkit-scrollbar{ width:0; height:0 }
.ds-panel-nav a{ font-family:var(--ds-menu-font, var(--ds-font-heading));
  font-size:var(--ds-panel-size,28px); font-weight:var(--ds-menu-weight,500);
  text-transform:var(--ds-menu-case,none); text-decoration:none; display:inline-block }
/* Anything else in the panel keeps whatever it was built as - the cart is a
   flex row of a basket and a number, and inline-block took the number out
   of the row and put it underneath. */
.ds-panel a{ text-decoration:none }
/* visibility:inherit, not visible.
   A visible child inside a hidden parent is shown - so with the panel closed
   its own background was not painted but every submenu link in it was, and at
   a width where the panel exists that reads as the menu having opened itself. */
.ds-panel .sub-menu{ position:static; opacity:1; visibility:inherit; pointer-events:auto;
  background:none; border:0; padding:6px 0 0 18px; transform:none; min-width:0 }
/* The same size as the level above it. Six tenths of a size the panel already
   sets small left a third level at eight pixels, and a menu whose depth you can
   read off the type size is a menu with three type sizes in it. Depth is said
   by the indent. */
.ds-panel .sub-menu a{ font-size:var(--ds-panel-size,28px);
  padding:var(--ds-submenu-pad,8px 16px); padding-left:0 }

/* The panel's own link colors and spacing. Separate from the bar, because the
   panel is a different piece of design at a different size. */
/* Ink for every link in the panel; spacing only for the menu's own. The
   logo is a link too, and it was taking the item margin. */
.ds-panel a{ color:var(--ds-panel-ink) }
.ds-panel-nav a{ margin:var(--ds-panel-link-margin,0) }
.ds-panel a:hover,.ds-panel a:focus-visible{ color:var(--ds-panel-ink-hover) }

/* Weight under the cursor. --ds-w is the number menu.js works out for each
   link; without it every link falls back to the weight the menu is set to, so
   the rule is inert until something is being pointed at. A variable font moves
   through the weights, a static one steps between the faces it has. */
body.ds-mweight .ds-panel a{
  font-weight:var(--ds-w, var(--ds-menu-weight,500));
  transition:font-weight var(--ds-mweight-time,.25s) ease,
             color var(--ds-link-time,.2s) ease }

@media (prefers-reduced-motion: reduce){
  body.ds-mweight .ds-panel a{ transition:none }
}

/* A link that fills the panel has a hit area the whole way across, which is
   what a thumb expects. The list item stretches too, or the link fills only as
   much as the centred column gave it. */
body.ds-panel-fullw .ds-panel-nav li{ width:100% }
body.ds-panel-fullw .ds-panel-nav a{ display:block; width:100% }

/* A rule between links. On the item rather than the link, so it spans the full
   width even when the link does not, and :last-child keeps a trailing line off
   the bottom of the list. */
/* The dividers belong to the menu, not to everything in the panel.

   The social microwidget is a list, so a rule aimed at li drew a menu
   divider under every icon - the row at the bottom came out looking like
   three more menu items. Aimed at the navigation, which is what the setting
   is about. */
/* Inside the rule, so it is space between the word and the line rather
   than between one row and the next - which is Link margin's job. */
.ds-panel-nav li{ padding:var(--ds-panel-link-pad, 0) }
body.ds-panel-rules .ds-panel-nav li{ border-bottom:1px solid var(--ds-panel-divider) }
body.ds-panel-rules .ds-panel-nav li:last-child{ border-bottom:0 }
body.ds-panel-rules .ds-panel-nav .sub-menu li:last-child{ border-bottom:0 }

/* Collapsed branches, when one parent at a time is asked for. */
body.ds-panel-accordion .ds-panel li.menu-item-has-children > .sub-menu{ display:none }
body.ds-panel-accordion .ds-panel li.menu-item-has-children.is-open > .sub-menu{ display:flex }

/* The close control sits in the panel's corner rather than in the flow, where
   it was pushing the first link down. Shown whenever the panel is - including
   under Always links, where the header's burger is hidden by a rule this one
   must not answer to. */
.ds-panel .ds-close{ position:absolute; top:var(--ds-panel-close-top,18px);
  /* Position hands the one inset to whichever side was chosen, so
     switching sides does not throw away the figure. */
  right:var(--ds-panel-close-side,18px); left:auto; z-index:2;
  display:flex !important; align-items:center; justify-content:center;
  flex-direction:column; gap:6px; cursor:pointer;
  /* The same box the burger is given, so the two rows on the Hamburger card
     mean one thing wherever the icon is drawn. Margin still reads as an offset
     here because the button is positioned rather than in the flow. */
  padding:var(--ds-close-pad,8px);
  margin:var(--ds-close-margin, 0);
  background:var(--ds-burger-bg,transparent);
  border:var(--ds-burger-border,0) solid var(--ds-burger-edge,transparent);
  border-radius:var(--ds-burger-radius,0) }
.ds-panel .ds-close:hover,
.ds-panel .ds-close:focus-visible{
  background:var(--ds-burger-bg-hover, var(--ds-burger-bg,transparent));
  border-color:var(--ds-burger-edge-hover, var(--ds-burger-edge,transparent)) }
.ds-panel .ds-close i{ display:block; width:24px; height:2px; border-radius:2px;
  background:var(--ds-menuclose-ink, var(--ds-burger-ink, currentColor));
  transition:transform .3s cubic-bezier(.7,0,.3,1), opacity .2s ease, background .16s ease }
.ds-panel .ds-close:hover i,
.ds-panel .ds-close:focus-visible i{
  background:var(--ds-menuclose-ink-hover,
    var(--ds-menuclose-ink, var(--ds-burger-ink-hover, var(--ds-burger-ink, currentColor)))) }

/* The shape, from the same setting the header burger reads. The bars are the
   three the button holds, so each option is the same geometry as its preview. */
body.ds-menuclose-morph .ds-panel .ds-close i:nth-child(1){ transform:translateY(8px) rotate(45deg) }
body.ds-menuclose-morph .ds-panel .ds-close i:nth-child(2){ opacity:0 }
body.ds-menuclose-morph .ds-panel .ds-close i:nth-child(3){ transform:translateY(-8px) rotate(-45deg) }

body[class*="ds-menuclose-cross"] .ds-panel .ds-close i:nth-child(2){ opacity:0 }
body[class*="ds-menuclose-cross"] .ds-panel .ds-close i:nth-child(1){
  width:var(--ds-x-len,22px); height:var(--ds-x-bar,2px); transform:translateY(8px) rotate(45deg) }
body[class*="ds-menuclose-cross"] .ds-panel .ds-close i:nth-child(3){
  width:var(--ds-x-len,22px); height:var(--ds-x-bar,2px); transform:translateY(-8px) rotate(-45deg) }
body.ds-menuclose-at-left .ds-panel .ds-close{
  left:var(--ds-panel-close-side,18px); right:auto }

body.ds-menuclose-cross-light .ds-panel .ds-close{ --ds-x-len:22px; --ds-x-bar:1px }
body.ds-menuclose-cross-bold  .ds-panel .ds-close{ --ds-x-len:22px; --ds-x-bar:3px }
body.ds-menuclose-cross-large .ds-panel .ds-close{ --ds-x-len:30px; --ds-x-bar:2px }
body.ds-menuclose-cross-small .ds-panel .ds-close{ --ds-x-len:15px; --ds-x-bar:2px }

body.ds-menuclose-minus .ds-panel .ds-close i:nth-child(1),
body.ds-menuclose-minus .ds-panel .ds-close i:nth-child(3){ opacity:0 }

/* The word, which is the close_word setting written into a property. */
body.ds-menuclose-word .ds-panel .ds-close i{ opacity:0 }
body.ds-menuclose-word .ds-panel .ds-close::after{
  content:var(--ds-menuclose-word,'Close'); position:absolute; inset:0;
  display:flex; align-items:center; justify-content:center; white-space:nowrap;
  font-size:13px; letter-spacing:.06em;
  color:var(--ds-menuclose-ink, var(--ds-burger-ink, currentColor)) }

/* The scene sits behind the links, filling the panel. pointer-events off so it
   is scenery rather than something that swallows a tap meant for a menu item -
   the camera is driven by hovering the links, not by dragging the model. */
.ds-panel-scene{ position:absolute; inset:0; width:100%; height:100%;
  z-index:0; pointer-events:none; --poster-color:transparent }
.ds-panel-scene::part(default-progress-bar){ display:none }
.ds-panel .ds-panel-nav,.ds-panel ul{ position:relative; z-index:1 }

/* ---- how the links arrive ----
 *
 * On the items rather than on the list, so one by one is possible at all. The
 * delay is on both states, which is what makes closing run the same cascade
 * backwards instead of the menu simply vanishing.
 *
 * --i is the item's place in the list, written on by menu.js. Without it every
 * delay would be the same and one by one would be all at once. */
.ds-mlink-fade .ds-panel-nav li,
.ds-mlink-stagger .ds-panel-nav li{
  opacity:0; transition:opacity var(--ds-mlink-time,.4s) ease }
.ds-mlink-fade .ds-panel-nav.is-lit li,
.ds-mlink-stagger .ds-panel-nav.is-lit li{ opacity:1 }

/* Up, not down.
 *
 * A transform below the content box is scrollable overflow, so six pixels of
 * offset on the last link was enough to put a scrollbar on the panel for as
 * long as the animation ran - on a menu of five items that fits the screen
 * twice over. Above the start edge is not scrollable, so the same movement
 * costs nothing and the links settle into place instead of rising into it. */
.ds-mlink-stagger .ds-panel-nav li{
  transform:translateY(-6px);
  transition:opacity var(--ds-mlink-time,.4s) ease,
             transform var(--ds-mlink-time,.4s) cubic-bezier(.22,1,.36,1);
  transition-delay:calc(var(--i,0) * var(--ds-mlink-step,60ms)) }
/* Leaving, from the last link back to the first.
 *
 * Only while the menu is closing. Arriving is always first to last - a menu
 * that came in backwards would read as a mistake - and this is the option that
 * says the way out is the way in, played in reverse. */
/* Quicker on the way out, whichever direction it runs in.
 *
 * A menu arriving can take its time - somebody is watching it. Leaving is the
 * answer to a button they just pressed, and at the full pace the top of the
 * list, which is where the eye is, sat there for a second before anything
 * moved. Same order, same cascade, roughly half the clock. */
body:not(.ds-menu-open) .ds-panel-nav li{
  transition-duration:calc(var(--ds-mlink-time,.4s) * var(--ds-mlink-out,.45));
  transition-delay:calc(var(--i,0) * var(--ds-mlink-step,60ms) * var(--ds-mlink-out,.45)) }

/* Reversed, and still on the quicker clock. */
body.ds-mlink-rev:not(.ds-menu-open) .ds-panel-nav li{
  transition-delay:calc(var(--r,0) * var(--ds-mlink-step,60ms) * var(--ds-mlink-out,.45)) }

.ds-mlink-stagger .ds-panel-nav.is-lit li{ transform:none }

@media (prefers-reduced-motion: reduce){
  .ds-mlink-fade .ds-panel-nav li,
  .ds-mlink-stagger .ds-panel-nav li{
    opacity:1; transform:none; transition:none; transition-delay:0s }
}

/* Alignment is a text question. Shrinking each item to its own word took
   the rule under it down to the width of that word, and a divider that
   stops after "Shop" is not a divider. The item stays the full width and
   the text moves inside it. */
.ds-panel-nav ul{ align-items:stretch }
.ds-panel-align-left   .ds-panel-nav ul{ text-align:left }
.ds-panel-align-center .ds-panel-nav ul{ text-align:center }
.ds-panel-align-right  .ds-panel-nav ul{ text-align:right }

/* Centred means centred, at every depth.
 *
 * A branch is indented eighteen pixels and its links carry the padding on one
 * side only - both fine against a left edge, and both a shift off the middle
 * when the menu is centred: half the indent plus half the padding, compounding
 * once per level, which put the third level sixteen pixels right of centre. So
 * centred drops the indent and pads evenly, and right aligned mirrors them. */
.ds-panel-align-center .ds-panel .sub-menu{ padding-left:0; padding-right:0 }
.ds-panel-align-center .ds-panel .sub-menu a{ padding-inline:0 }

.ds-panel-align-right .ds-panel .sub-menu{ padding-left:0; padding-right:18px }
.ds-panel-align-right .ds-panel .sub-menu a{ padding-left:0; padding-right:0 }

/* Reversed.
 *
 * A wipe reverses by starting from the other side, which is the opposite wipe -
 * so the four of them are written once more the other way about rather than as
 * four more options in the list. A shader reverses by mirroring the quad it
 * draws on: every one of them is a full screen pass reading its own position,
 * so flipping that position flips melt, shutter, reveal and the rest without
 * any of them being edited. */
body.ds-panel-rev:not(.ds-menu-open).ds-panel-wipe-right .ds-panel{ transform:translateX(-100%) }
body.ds-panel-rev:not(.ds-menu-open).ds-panel-wipe-left  .ds-panel{ transform:translateX(100%) }
body.ds-panel-rev:not(.ds-menu-open).ds-panel-wipe-down  .ds-panel{ transform:translateY(100%) }
body.ds-panel-rev:not(.ds-menu-open).ds-panel-wipe-up    .ds-panel{ transform:translateY(-100%) }

/* The shader leaves the other way about by mirroring the quad it draws on -
   every one of them is a full screen pass reading its own position, so this
   flips melt, shutter, reveal and the rest without any of them being edited.
   Only while it is closing: ds-gl-shut is on for exactly that stretch.
 *
 * Not when there is a picture behind the menu. Mirroring the quad mirrors
 * everything drawn on it, and what is drawn on it then is the overlay's own
 * image - so the wipe took the picture away upside down. A pattern has no way
 * up and does not care; a photograph does. The reverse is still a reverse
 * either way, because the wipe runs its progress backwards regardless - this
 * only ever added which side it ran from. */
body.ds-panel-rev.ds-gl-shut:not(.ds-panelmedia-image):not(.ds-panelmedia-video):not(.ds-panelmedia-scene) .ds-panel-gl{
  transform:scale(-1) }

/* Closed states, one per animation. Opacity as well as transform on the wipes,
   so a panel on its way out is never briefly visible over the content. */
.ds-panel-fade       .ds-panel{ opacity:0 }
.ds-panel-wipe-right .ds-panel{ opacity:0; transform:translateX(100%) }
.ds-panel-wipe-left  .ds-panel{ opacity:0; transform:translateX(-100%) }
.ds-panel-wipe-down  .ds-panel{ opacity:0; transform:translateY(-100%) }
.ds-panel-wipe-up    .ds-panel{ opacity:0; transform:translateY(100%) }
/* The shader draws the arrival itself, so the panel is simply there and the
   canvas over it is what moves. Without WebGL the canvas stays empty and this
   rule is replaced by the wipe below, added by the script. */
/* Closed is closed, whatever draws the opening. This was left at opacity 1 for
   a shader to fade in over, which only works once there is a shader running. */
.ds-panel-shader .ds-panel{ opacity:0; transform:none }

/* ---- with a shader running ----
 *
 * Nothing here decides whether the menu is visible. That was the mistake: the
 * panel, the links and the close control were all gated on the shader having
 * covered the screen, so any frame the shader did not draw took the whole menu
 * with it - and it did not draw far more often than it did.
 *
 * The menu is CSS, start to finish. The canvas is a decoration laid over the
 * top: it covers the screen and clears to reveal a menu that was already there,
 * and covers it again on the way out. If it never draws at all, the menu opens
 * and closes exactly as it would without it. */
body.ds-gl-on.ds-panel-shader .ds-panel{ opacity:1 }
body.ds-gl-on.ds-panel-shader.ds-menu-open .ds-panel{ opacity:1; visibility:visible }

/* One picture on screen, never two.
 *
 * While the shader is drawing, the panel shows nothing at all. Both of them
 * carry the same image, and fading the panel up underneath a wipe that is
 * drawing that same image meant two copies of it on screen at once, one of them
 * half there. The panel appears on the frame the wipe ends and the canvas goes
 * on that same frame - identical pictures, so the handover cannot be seen. */
/* While the shader draws, the panel is a frame for the canvas and nothing else.
 *
 * It stays visible - the canvas is its child, and a hidden parent hides the
 * drawing with it - but shows none of its own: no colour, no picture, nothing
 * in it. On the way in that is one picture on screen instead of two. On the way
 * out it is what lets the wipe run over the page after the menu has gone.
 *
 * One class for both directions. Holding the panel open with a separate closing
 * class is what left the picture stuck on screen when that class was not taken
 * off again. */
/* Held open while its links leave.
 *
 * The panel closes on its own clock the moment the menu is dismissed, which
 * put the picture off the screen before the cover had arrived to take it
 * away - and the wipe then brought the whole picture back on to wipe it off.
 * Nothing moves out here until the cover is over the top of it.
 *
 * Before the wiping rules below, so that when the cover is up they win and the
 * panel goes blank behind it. */
body.ds-gl-on.ds-gl-shut.ds-panel-shader .ds-panel{
  visibility:visible; opacity:1; transform:none; transition:none }

/* Blank is the default, not something switched on when the wipe starts.
 *
 * Waiting for a class to arrive means there is a frame where the class has not
 * arrived yet - the menu is open, the panel is showing its picture, and the
 * cover has not been told to draw. That frame is the image flashing up the
 * instant the hamburger is pressed. So the panel shows nothing from the moment
 * it opens and only takes its own background once the wipe hands over. */
body.ds-gl-on.ds-gl-wiping.ds-panel-shader .ds-panel,
body.ds-gl-on.ds-panel-shader.ds-menu-open:not(.ds-gl-done) .ds-panel{
  visibility:visible; opacity:1; transition:none;
  background-color:transparent; background-image:none }

body.ds-gl-on.ds-gl-wiping.ds-panel-shader .ds-panel > *:not(.ds-panel-gl),
body.ds-gl-on.ds-panel-shader.ds-menu-open:not(.ds-gl-done) .ds-panel > *:not(.ds-panel-gl){
  opacity:0; transition:none }

body.ds-gl-on.ds-gl-wiping.ds-panel-shader .ds-panel::before,
body.ds-gl-on.ds-panel-shader.ds-menu-open:not(.ds-gl-done) .ds-panel::before{
  opacity:0 }

/* Gone the moment the cover has finished with it.
 *
 * In shader mode the panel never animates itself - the cover does all of it -
 * but it still carried the overlay's transition, and visibility only flips at
 * the end of one. So the wipe finished, the panel took its picture back, and
 * sat there fully painted for the whole of the overlay time before the
 * transition finally hid it. That is the image coming back after everything
 * has closed and hanging about.
 *
 * The three exceptions are the three states that are still using it: the menu
 * open, the links leaving, and the cover drawing. */
body.ds-gl-on.ds-panel-shader:not(.ds-menu-open):not(.ds-gl-shut):not(.ds-gl-wiping) .ds-panel{
  opacity:0; visibility:hidden; transition:none }

/* On screen only while it is drawing, so a frame from the way in cannot flash
   up on the way out. */
body.ds-gl-on.ds-panel-shader .ds-panel-gl{ z-index:3; opacity:0 }
body.ds-gl-on.ds-gl-cover.ds-panel-shader .ds-panel-gl{ opacity:1 }


/* Nothing here holds the cross back while a shader runs.
 *
 * It used to, and that is where the gap came from. The links start their
 * cascade the moment the menu opens and run it underneath the cover, so the
 * last one lands on the clock it was given. Holding the cross until the cover
 * had cleared restarted its delay from that point instead - the whole cover
 * time, added on after the last link had already arrived. It is hidden anyway
 * until its own turn, and the cover is painted over the top of it in the
 * meantime, so there is nothing to hold back. */
.ds-panel-shader.ds-gl-off .ds-panel{ opacity:0; transform:translateX(100%) }

/* Fixed to the window, not to the panel.
 *
 * Absolute inside the panel meant the cover stopped wherever the panel's own
 * margin put its edges - a menu with any margin on it had a wipe that left a
 * frame of untouched page around the outside. A full screen quad should cover
 * the full screen. */
.ds-panel-gl{ position:fixed; inset:0; width:100vw; height:100vh; height:100dvh;
  z-index:3; display:block; pointer-events:none }
.ds-gl-off .ds-panel-gl{ display:none }

body.ds-menu-open .ds-panel{ opacity:1; transform:none; visibility:visible }
/* The page does not scroll while the menu is over it - and does not jump when
   it stops. Taking the scrollbar away frees its width and every centred thing
   on the page slides across; the gutter is reserved either way instead, so
   opening the menu changes nothing but the overlay. */
/* The page does not scroll while the menu is over it, and does not jump when it
   stops.
 *
 * scrollbar-gutter is no use here: it reserves space for a scrollbar an element
 * would have, and an element with overflow:hidden has none - so the ten pixels
 * came back the moment the menu opened and everything centred slid across. The
 * width of the bar is measured as it is taken away and handed back as padding,
 * which is the only way the page keeps the same measure. A fixed overlay is
 * laid out against the viewport, so this does not move the menu itself.
 *
 * Held until the overlay has actually gone, not until the menu is dismissed.
 * The links leave and the cover wipes back off the page after that, and handing
 * the scrollbar back at the click jumped the page a bar's width while the
 * overlay was still on screen. ds-menu-shut covers the panel animating out and
 * ds-gl-shut and ds-gl-wiping the links and the cover, so between them the lock
 * lasts exactly as long as there is something over the page. */
html:has(body.ds-menu-open),
html:has(body.ds-menu-shut),
html:has(body.ds-gl-shut),
html:has(body.ds-gl-wiping){ overflow:hidden }

/* And the width handed back to whatever is actually holding the page.
 *
 * On the root it did nothing: the smooth scroller wraps everything in a fixed
 * box, and a fixed box is laid out against the viewport - which is precisely
 * the thing that got ten pixels wider. So the padding goes on that box where
 * there is one, and on the body where there is not. */
html:has(body.ds-menu-open) #smooth-wrapper,
html:has(body.ds-menu-shut) #smooth-wrapper,
html:has(body.ds-gl-shut) #smooth-wrapper,
html:has(body.ds-gl-wiping) #smooth-wrapper,
body.ds-menu-open,
body.ds-menu-shut,
body.ds-gl-shut,
body.ds-gl-wiping{ padding-right:var(--ds-lockpad,0px) }

@media (prefers-reduced-motion:reduce){
  .ds-panel, .ds-nav .sub-menu{ transition-duration:1ms }
}


/* ScrollSmoother needs its wrapper fixed to the viewport and its content free
   to be moved. Without this the page scrolls twice - once natively and once
   under the transform. */
/* Behind the page, and behind everything on it.
 *
 * Fixed rather than painted on the body: a body background cannot be held
 * still while a smooth scroller moves the content, and a scene is an element
 * rather than a paint. Scenery, so it takes no clicks. */
.ds-page-bg,.ds-page-scene,.ds-page-gl{
  position:absolute; inset:0; z-index:-1; pointer-events:none;
  width:100%; height:100% }
.ds-page-bg.is-fixed,.ds-page-scene,.ds-page-gl{ position:fixed }
.ds-page-bg{
  background-image:var(--ds-page-img);
  background-size:var(--ds-page-fit,cover);
  background-position:var(--ds-page-pos,center);
  background-repeat:no-repeat }
.ds-page-scene{ --poster-color:transparent }
.ds-page-scene::part(default-progress-bar){ display:none }

/* Where the model sits and how big it is drawn is no longer said here.
 *
 * It used to be a transform on this element, which had two faults. The rule
 * named .ds-page-scene and the badge in the footer is .ds-footer-scene, so the
 * scale and placement figures were written onto it and read by nothing at all.
 * And where the rule did apply it scaled a picture the canvas had already
 * drawn, so a model at 200% was the same pixels blown up to twice the size.
 *
 * The renderer does both now, from the same figures, drawn at the size asked
 * for and sharp - and the footer answers to them like everything else. */
.ds-page-scene{ transition:opacity .3s linear }

/* Drifting.
 *
 * On the wrapper, not the camera - a camera that moves changes the perspective
 * and the model appears to swim rather than to float. The whole layer rising
 * and falling keeps the shape rigid, which is what reads as weight. Composed
 * with the placement above by moving the drift onto its own axis. */
@keyframes ds-model-drift{
  0%,100%{ translate:0 -1.2% }
  50%    { translate:0 1.2% } }
.ds-page-scene.is-drifting{
  animation:ds-model-drift 7s cubic-bezier(.45,0,.55,1) infinite }

@media (prefers-reduced-motion:reduce){
  .ds-page-scene.is-drifting{ animation:none }
}

/* A colour behind the page, where one is set. The palette's own colour is the
   fallback, so a site that sets nothing looks exactly as it did.
 *
 * On html only. A negative z-index child of body paints before body's own
 * background, not after - so an opaque colour on body covered the picture and
 * the shader layer completely, and a background that was loaded, sized and
 * positioned correctly was simply underneath something. */
html{ background-color:var(--ds-page-bg, var(--ds-bg)) }
body{ background-color:transparent }

/* Except while smooth scrolling is driving the page.
 *
 * The wrapper below is fixed over the whole window and its content is moved by
 * a transform. Between frames the browser has the wrapper to paint and a body
 * with no colour of its own behind it, and it fills that with its own default -
 * so scrolling a black site flashed white below the first screen, and white
 * text vanished into it.
 *
 * Only when the wrapper is actually there, and only when nothing is sitting
 * behind the page: a colour on body would cover a background picture or a
 * shader, which is the whole reason body is transparent to begin with. */
body:has(> #smooth-wrapper):not(:has(.ds-page-scene)):not(:has(.ds-page-bg)){
  background-color:var(--ds-page-bg, var(--ds-bg));
}

/* Only once the smoother has started.

   ScrollSmoother is not created on a touch screen or under reduced
   motion, and a fixed clipped wrapper with nothing driving it is a
   sealed box - the page showed one screenful and would not scroll. The
   class is written on <html> by the smoother's own boot, so until then
   this is an ordinary scrolling document. */
html.ds-smooth #smooth-wrapper{ overflow:hidden; position:fixed; height:100%; width:100%;
  top:0; left:0; right:0; bottom:0 }

/* Room for the admin bar, since nothing else makes any.
 *
 * WordPress moves the page down for its bar with a margin on html. A fixed
 * element is laid out against the viewport and not against that box, so the
 * margin does nothing to this wrapper - the site started at zero and its own
 * header sat underneath the admin bar for anybody logged in.
 *
 * The two figures are WordPress's own: 32px, and 46px on a narrow window where
 * the bar is taller. Only ever applied to a logged in page, because body only
 * carries admin-bar when the bar is actually there.
 *
 * important because ScrollSmoother writes inset and height onto this element
 * as inline styles, and an inline style beats any ordinary rule in a
 * stylesheet. An important author declaration is the one thing above it, and it
 * holds when the smoother rewrites those styles on a refresh. */
html.ds-smooth body.admin-bar #smooth-wrapper{
  top:32px !important;
  bottom:0 !important;
  height:calc(100% - 32px) !important }

@media screen and (max-width:782px){
  html.ds-smooth body.admin-bar #smooth-wrapper{
    top:46px !important;
    height:calc(100% - 46px) !important }
}
#smooth-content{ overflow:visible; width:100% }

/* No wrapper on the page means no smoothing, and nothing above applies. */

/* ---------------------------------------------------------------------
 * Buttons: the styles, the icon and the hovers
 *
 * Every color falls back to the palette, so a button that has not been
 * given its own colors still belongs to the scheme.
 *
 * Three steps, in this order: the button's own colour, then the palette's
 * Button and Button text, then the accent.
 *
 * The middle step was missing. The palette has had a Button swatch all along
 * and it is written out as --ds-btn-bg, but nothing read it - so setting the
 * Button colour in the palette changed nothing anywhere and buttons took the
 * accent instead. That is the whole reason the palette appeared not to reach
 * the Buttons tab.
 * ------------------------------------------------------------------ */
/* Every kind of button, not only the ones written as a link.
 *
 * This block sets the hover colours and the speed, and it named .ds-btn and a
 * block button. The rule that lays a button out further up also names
 * button.ds-btn and button[type=submit] - one class and one element, which
 * outranks a bare class - so a button that is a real <button> took its
 * transition from there instead: .16s against .35s here.
 *
 * That is why the shop's Search and Apply filled at twice the speed of every
 * other button on the site. The selectors are matched now, so a <button> and an
 * <a> are the same button. */
.ds-btn,
button.ds-btn,
input[type=submit],
button[type=submit],
.wp-block-button__link{
  --fill:var(--ds-btn-fill,var(--ds-btn-bg,var(--ds-accent,#fff)));
  --edge:var(--ds-btn-edge,var(--ds-btn-bg,var(--ds-accent,#fff)));
  --ink:var(--ds-btn-ink,var(--ds-btn-text,var(--ds-bg,#000)));
  /* Hover inverts by default: the page behind becomes the fill, and the
     button's own colour becomes the label. */
  --fill-h:var(--ds-btn-fill-hover,var(--ds-bg,#000));
  --edge-h:var(--ds-btn-edge-hover,var(--ds-btn-bg,var(--ds-accent,#fff)));
  --ink-h:var(--ds-btn-ink-hover,var(--ds-btn-bg,var(--ds-accent,#fff)));
  position:relative; overflow:hidden; isolation:isolate;
  display:inline-flex; align-items:center; gap:9px;
  transition:background var(--ds-btn-speed,.35s) ease,
             color var(--ds-btn-speed,.35s) ease,
             border-color var(--ds-btn-speed,.35s) ease,
             transform var(--ds-btn-speed,.35s) ease,
             box-shadow var(--ds-btn-speed,.35s) ease }

/* The magnet owns the transform while it is on.
   It writes an inline transform every frame with an ease of its own, and
   the transition above then eases each of those again - two curves over one
   movement, which reads as the button lagging behind the cursor on a
   rubber band rather than following it. */
.ds-magnet-attract .ds-btn,
.ds-magnet-repel .ds-btn{
  transition:background var(--ds-btn-speed,.35s) ease,
             color var(--ds-btn-speed,.35s) ease,
             border-color var(--ds-btn-speed,.35s) ease,
             box-shadow var(--ds-btn-speed,.35s) ease }

/* An icon in a button.
   The button is already a flex line with a gap, so the mark needs no placing -
   only a size that follows the label rather than a fixed 20px, and a refusal to
   be squashed when the button is narrow. It inherits currentColor, so it turns
   with the button on hover without a rule of its own. */

/* On an ancestor, and on the button itself.
 *
 * These were written as descendant selectors only, because the look used to be
 * one choice for the whole site set on the body. A Button element chooses its
 * own now and puts the class on the button - where .ds-btn-outline .ds-btn can
 * never match it. The body's class went on winning, so a button set to Outline
 * drew as a solid slab and answered to the solid colours. */
.ds-btn-solid .ds-btn:not(.ds-btn-secondary),
.ds-btn.ds-btn-solid{ background:var(--fill); color:var(--ink); border-color:var(--edge) }

/* Text colour is the button's own, not the line around it.
 *
 * This read color:var(--edge), so an outline button's label was always the
 * border colour and the Text colour on Theme Settings did nothing to it. The
 * border is still the fallback, so a site that never set one looks as it did. */
.ds-btn-outline .ds-btn:not(.ds-btn-solid):not(.ds-btn-secondary),
.ds-btn.ds-btn-outline{
  background:transparent;
  color:var(--ds-btn-ink, var(--edge));
  border-color:var(--edge);
}
.ds-btn-ghost .ds-btn:not(.ds-btn-solid):not(.ds-btn-secondary){ background:transparent; color:var(--edge); border-color:transparent }
.ds-btn-underline .ds-btn:not(.ds-btn-solid):not(.ds-btn-secondary){ background:transparent; color:var(--edge); border:0;
  border-radius:0; padding-inline:0; border-bottom:1px solid currentColor }

/* the icon

   Two things put a mark on a button and they do not agree on a class name. The
   Buttons tab draws its own small SVG as .ds-btn-ico; a button built in the page
   builder takes any icon from the enabled sets, and that arrives as .ds-icon.

   Everything below named only the first, so a builder button's icon was sized by
   a different rule, carried no transition, and none of the three motions ever
   applied to it. Both are named now, and both are sized the same, so an icon is
   the same icon wherever it was chosen. */
.ds-btn > .ds-btn-ico,
.ds-btn > .ds-icon{ width:1.15em; height:1.15em; flex:0 0 auto;
  transition:transform var(--ds-btn-speed,.35s) cubic-bezier(.22,1,.36,1) }

.ds-btnicon-slide .ds-btn:hover > .ds-btn-ico,
.ds-btnicon-slide .ds-btn:hover > .ds-icon{ transform:translateX(5px) }
.ds-btnicon-rotate .ds-btn:hover > .ds-btn-ico,
.ds-btnicon-rotate .ds-btn:hover > .ds-icon{ transform:rotate(45deg) }
.ds-btnicon-pop .ds-btn:hover > .ds-btn-ico,
.ds-btnicon-pop .ds-btn:hover > .ds-icon{ transform:scale(1.35) }

/* the hovers that are only CSS */
.ds-hover-default .ds-btn:hover,
.ds-hover-invert .ds-btn:hover{ background:var(--fill-h); color:var(--ink-h); border-color:var(--edge-h) }
.ds-hover-glow .ds-btn:hover{ box-shadow:0 0 0 1px var(--edge-h), 0 0 34px -6px var(--edge-h) }

.ds-hover-wipe .ds-btn::before,.ds-hover-wipeup .ds-btn::before{
  content:''; position:absolute; inset:0; z-index:-1; background:var(--fill-h);
  transform-origin:0 50%; transform:scaleX(0);
  transition:transform var(--ds-btn-speed,.35s) cubic-bezier(.22,1,.36,1) }
.ds-hover-wipeup .ds-btn::before{ transform-origin:50% 100%; transform:scaleY(0) }
.ds-hover-wipe .ds-btn:hover::before{ transform:scaleX(1) }
.ds-hover-wipeup .ds-btn:hover::before{ transform:scaleY(1) }
.ds-hover-wipe .ds-btn:hover,.ds-hover-wipeup .ds-btn:hover{ color:var(--ink-h); border-color:var(--edge-h) }

/* the fill that starts where the cursor entered - the circle is placed by
   assets/buttons.js, the size and the color are here */
/* The disc that grows from where the cursor came in.

   It has to be at least twice the button's diagonal, because it is centred
   on wherever the pointer entered and still has to reach the far corner from
   there. Two hundred per cent of the width is that figure for a button of no
   height at all, so anything under it stops short on the wide ones - which is
   what happened when this was tried at a hundred and fifty. Three hundred
   covers a button half as tall as it is wide with room to spare.

   How fast it arrives is the tween in buttons.js, not this. */
.ds-btn-ink{ position:absolute; z-index:-1;
  width:var(--ds-btn-ink-size,300%); aspect-ratio:1;
  margin:calc(var(--ds-btn-ink-size,300%) / -2) 0 0 calc(var(--ds-btn-ink-size,300%) / -2);
  border-radius:50%; background:var(--fill-h);
  transform:scale(0); pointer-events:none }
/* Keyed to the class the script sets, not to :hover - the fill outlives the
   hover by a few hundred milliseconds, and the text has to stay readable for
   exactly as long as the fill is there. :hover is kept as a fallback for a
   pointer that never fires pointerenter at all. */
/* The edge and the label change over the same time the disc takes to cross.
 *
 * The button clips its own overflow, so the disc cannot paint the border - the
 * border has to travel by itself. On the button's ordinary speed it arrived a
 * third of a second in, long before the fill behind it, and a red border on a
 * button filling to white had already turned while most of the button was still
 * red. buttons.js publishes the disc's duration as --ds-fill-dur and this reads
 * it, so the two land together whatever the speed is set to. */
.ds-hover-cursorfill .ds-btn.is-filling,
.ds-hover-cursorfill .ds-btn:hover{
  color:var(--ink-h); border-color:var(--edge-h);
  transition:color var(--ds-fill-dur, var(--ds-btn-speed,.35s)) ease,
             border-color var(--ds-fill-dur, var(--ds-btn-speed,.35s)) ease }

@media (prefers-reduced-motion: reduce){
  .ds-btn,.ds-btn-ico,.ds-btn > .ds-icon,.ds-btn::before{ transition:none !important }
}


/* ---------------------------------------------------------------------
 * Behind the mobile menu
 *
 * The dim layer sits between the media and the links, so a photograph can be
 * used without the menu becoming unreadable over it.
 * ------------------------------------------------------------------ */
.ds-panelmedia-image .ds-panel{
  background-image:var(--ds-panel-img);
  background-position:var(--ds-panel-pos,center);
  background-repeat:no-repeat }
.ds-panelfit-cover.ds-panelmedia-image .ds-panel{ background-size:cover }
.ds-panelfit-contain.ds-panelmedia-image .ds-panel{ background-size:contain }
.ds-panelfit-fill.ds-panelmedia-image .ds-panel{ background-size:100% 100% }
.ds-panelfit-none.ds-panelmedia-image .ds-panel{ background-size:auto }
.ds-panelfit-repeat.ds-panelmedia-image .ds-panel{ background-size:auto;
  background-repeat:repeat }

.ds-panel-video{ position:absolute; inset:0; width:100%; height:100%;
  object-position:var(--ds-panel-pos,center); z-index:0; pointer-events:none }
.ds-panelfit-cover .ds-panel-video{ object-fit:cover }
.ds-panelfit-contain .ds-panel-video{ object-fit:contain }
.ds-panelfit-fill .ds-panel-video{ object-fit:fill }
.ds-panelfit-none .ds-panel-video{ object-fit:none }
.ds-panelfit-repeat .ds-panel-video{ object-fit:cover }

.ds-panel-scene{ position:absolute; inset:0; width:100%; height:100%;
  z-index:0; display:block }

/* With a picture, a video or a scene behind the menu, the panel's own colour is
   not painted over it - the dim below is what darkens it, and having both meant
   the overlay colour tinted the picture as well. */
.ds-panelmedia-image .ds-panel,
.ds-panelmedia-video .ds-panel,
.ds-panelmedia-scene .ds-panel{ background-color:transparent }

/* One layer for all three, so the dim reads the same whatever is behind. */
.ds-panelmedia-image .ds-panel::before,
.ds-panelmedia-video .ds-panel::before,
.ds-panelmedia-scene .ds-panel::before{
  content:''; position:absolute; inset:0; z-index:1; pointer-events:none;
  background:var(--ds-panel-bg, var(--ds-bg,#0b0b0c));
  opacity:var(--ds-panel-dim,.4) }

/* The canvas is left out of all three.
 *
 * These lift the panel's contents above the dim layer by giving them a position
 * of their own - and the cover is a child too, so with a picture behind the
 * menu it was being turned back into a relatively positioned box the size of
 * the panel. That is the shader not covering the screen. */
.ds-panelmedia-image .ds-panel > *:not(.ds-panel-gl):not(.ds-close),
.ds-panelmedia-video .ds-panel > *:not(.ds-panel-video):not(.ds-panel-gl):not(.ds-close),
.ds-panelmedia-scene .ds-panel > *:not(.ds-panel-scene):not(.ds-panel-gl):not(.ds-close){
  position:relative; z-index:2 }

/* The cross keeps its corner. These rules hand every child a position of its
   own to lift it above the dim layer, and position:relative on something that
   was absolute drops it back into the flow - which in a centred column is the
   middle of the screen. That is the close button appearing in the centre the
   moment a picture was set behind the menu. */
.ds-panelmedia-image .ds-panel > .ds-close,
.ds-panelmedia-video .ds-panel > .ds-close,
.ds-panelmedia-scene .ds-panel > .ds-close{ position:absolute; z-index:4 }


/* The end items sit flush with the edge of the header.
   Only the outer side is trimmed - the first item keeps its right padding and
   the last keeps its left, so the hit area between items is unchanged and only
   the alignment against the container edge moves. */
.ds-menu-flush .ds-nav > ul > li:first-child > a{ padding-left:0 }
.ds-menu-flush .ds-nav > ul > li:last-child > a{ padding-right:0 }


/* ---------------------------------------------------------------------
 * The scrollbar
 *
 * Two syntaxes, because they are not interchangeable: scrollbar-color is the
 * standard one and is all Firefox understands, ::-webkit-scrollbar is the old
 * one and is the only way to set a width in Safari. Both are written, and a
 * browser uses whichever it knows.
 * ------------------------------------------------------------------ */
.ds-scrollbar-styled{
  scrollbar-width:thin;
  scrollbar-color:var(--ds-scrollbar-thumb, var(--ds-text,#f5f5f5))
                  var(--ds-scrollbar-track, var(--ds-bg,#0b0b0c)) }
.ds-scrollbar-styled ::-webkit-scrollbar,
.ds-scrollbar-styled::-webkit-scrollbar{ width:var(--ds-scrollbar-w,10px); height:var(--ds-scrollbar-w,10px) }
.ds-scrollbar-styled ::-webkit-scrollbar-track,
.ds-scrollbar-styled::-webkit-scrollbar-track{ background:var(--ds-scrollbar-track, var(--ds-bg,#0b0b0c)) }
.ds-scrollbar-styled ::-webkit-scrollbar-thumb,
.ds-scrollbar-styled::-webkit-scrollbar-thumb{
  background:var(--ds-scrollbar-thumb, var(--ds-text,#f5f5f5));
  border-radius:var(--ds-scrollbar-radius,10px) }

/* Hidden, not disabled - the page still scrolls by wheel, key and touch. */
.ds-scrollbar-hidden{ scrollbar-width:none; -ms-overflow-style:none }
.ds-scrollbar-hidden ::-webkit-scrollbar,
.ds-scrollbar-hidden::-webkit-scrollbar{ width:0; height:0; display:none }

/* ---- social marks in the footer ---- */

/* An icon is a link with no words in it, so it needs a hit area of its own
   rather than inheriting the height of text that is not there. */
/* Every part of a social mark is a setting: the mark size, the gap between
   them, the hit area behind it, its corner, and four colors. Hardcoded before,
   which made the one row on the footer that could not be changed at all. */
/* No alignment of its own. The marks are a microwidget now and sit wherever the
   end holding them puts its items, the same as every other one - a second
   alignment on the list itself only fought whichever end it was in. */
.ds-footer-social{ gap:var(--ds-social-gap,22px);
  /* The marks centred on their own line, not sitting at the top of it.
   *
   * The list is a flex row with no alignment set, so its items lined up at the
   * start of the cross axis - and the row is as tall as its line height, which
   * is taller than a 16px mark. That is a mark nine pixels from the top of the
   * row and fifteen from the bottom, in a bar that had centred the row itself
   * perfectly. Nothing was wrong with the bar or with anybody's spacing. */
  align-items:center;
  /* And the row is the height of the marks in it, so there is no leading to
     centre inside in the first place. */
  line-height:1 }

/* No line box around the mark.
 *
 * The link is an inline-flex box, which sits on a baseline - so the item around
 * it grew to fit the font's descender underneath, two pixels that only ever
 * appear below. A flex item has no baseline to sit on and no descender to make
 * room for, so the item is the height of the mark and nothing else. */
.ds-footer-social li{ display:flex; align-items:center }

/* The first mark lines up with the words above it.
 *
 * Each link is a hit area - 38px by default - with a 20px mark centered in it,
 * so the ink of the first icon started nine pixels in from the edge of the
 * column while the heading above it started at zero. No setting could fix that:
 * every one of them moves both edges together, and shrinking the hit area to
 * close the gap takes the tap target with it.
 *
 * The row is pulled back by half the difference instead. The hit area keeps its
 * full size, the ink lines up with the heading, and it stays lined up whatever
 * the size and hit settings are changed to. Only where the row is left aligned -
 * centered or right, the edge is not what it is being measured against. */
.ds-fb-social .ds-footer-social{
  margin-left:calc(var(--ds-social-nudge,9px) * -1);
  margin-right:calc(var(--ds-social-nudge,9px) * -1);
}
.ds-footer-social a{ display:inline-flex; align-items:center; justify-content:center;
  width:var(--ds-social-hit,38px); height:var(--ds-social-hit,38px);
  border-radius:var(--ds-social-radius,50%);
  color:var(--ds-social-ink,currentColor);
  background:var(--ds-social-bg,transparent);
  transition:color .16s ease, background .16s ease }
.ds-footer-social a:hover,.ds-footer-social a:focus-visible{
  color:var(--ds-social-ink-hover);
  background:var(--ds-social-bg-hover) }
/* Said again for the top bar, whose own link rule is a class more specific than
   the one above - so the marks in the bar came out the bar's link color while
   the same marks in a sidebar or the footer came out the one that was set. */
.ds-bar .ds-footer-social a{ color:var(--ds-social-ink,currentColor) }
.ds-bar .ds-footer-social a:hover,
.ds-bar .ds-footer-social a:focus-visible{ color:var(--ds-social-ink-hover) }
/* The mark is the size it is told to be, on both axes.
 *
 * The sheet caps every img, svg and video at 100% of its parent, which is right
 * for a picture in a column and wrong for a mark whose parent is sized by the
 * mark. Height grew and width stayed where it was, so a bar that asked for
 * 28px got a 16 by 28 rectangle. */
.ds-social-mark{ display:block; flex:0 0 auto; max-width:none;
  width:var(--ds-social-size,20px); height:var(--ds-social-size,20px) }

/* A service with no mark still shows its name, so that one keeps reading as a
   word rather than being squeezed into a circle. */
.ds-footer-social a:not(:has(.ds-social-mark)){ width:auto; height:auto; border-radius:0 }

/* ==================================================================
   Lists of posts, and the inside of one
   ==================================================================
   The templates have always printed these classes; nothing was ever written to
   style them, so a blog, an archive, a search result and the body of a post all
   came out as unstyled browser defaults on a theme that is otherwise finished.

   Everything here is the site's own palette and type scale. A post is the one
   page a visitor reads rather than looks at, so it is a column of prose at the
   reading measure, and the pieces that are not prose - a lead image, a pull
   quote - are the ones allowed out of it.
   ================================================================== */

/* ---- the heading over a list ---- */
.ds-list-head{ max-width:var(--ds-read,72ch); margin:0 auto 2.5rem }
.ds-list-title{ margin:0 0 .3em; font-size:var(--ds-h1-size);
  font-weight:var(--ds-h1-weight); text-transform:var(--ds-h1-case);
  line-height:var(--ds-h1-lh,1em) }
.ds-list-intro{ color:var(--ds-accent) }
.ds-list-intro > :last-child{ margin-bottom:0 }

/* ---- the cards ----
   As many columns as the width allows, and never narrower than a card can be
   read at. auto-fill rather than auto-fit: with one post, auto-fit stretches
   that card across the whole page and it stops looking like a card. */
.ds-list{ display:grid; gap:var(--ds-gutter,24px);
  grid-template-columns:repeat(auto-fill,minmax(300px,1fr)) }

.ds-card{ display:flex; flex-direction:column; min-width:0;
  background:color-mix(in srgb, var(--ds-text) 4%, transparent);
  border:1px solid var(--ds-line);
  border-radius:var(--ds-field-radius,4px); overflow:hidden }
.ds-card:hover{ border-color:color-mix(in srgb, var(--ds-text) 28%, transparent) }

/* A picture that fills its box whatever shape it was uploaded at, so a row of
   cards has one skyline rather than five. */
.ds-card-media{ display:block; aspect-ratio:16/10; overflow:hidden }
.ds-card-media img{ width:100%; height:100%; object-fit:cover; display:block;
  transition:transform .5s ease }
.ds-card:hover .ds-card-media img{ transform:scale(1.03) }

.ds-card-body{ display:flex; flex-direction:column; gap:10px;
  padding:20px; flex:1 1 auto }

.ds-card-title{ margin:0; font-size:var(--ds-h4-size);
  font-weight:var(--ds-h4-weight); text-transform:var(--ds-h4-case);
  line-height:var(--ds-h4-lh,1em) }
.ds-card-title a{ color:var(--ds-heading); text-decoration:none }
.ds-card-title a:hover{ color:var(--ds-link-hover) }

.ds-card-excerpt{ color:var(--ds-text); font-size:15px }
.ds-card-excerpt p{ margin:0 }

/* Pushed to the foot of the card, so the link sits on one line across a row of
   cards whose titles and excerpts are all different lengths. */
.ds-card-more{ margin-top:auto; align-self:flex-start;
  font-size:14px; letter-spacing:.04em; text-decoration:none;
  color:var(--ds-link); border-bottom:1px solid currentColor; padding-bottom:2px }
.ds-card-more:hover{ color:var(--ds-link-hover) }

.ds-post-cats{ margin-left:10px }
.ds-post-cats a{ text-decoration:none }
.ds-post-cats a:hover{ text-decoration:underline }

/* ---- nothing to show ---- */
.ds-empty{ max-width:var(--ds-read,72ch); margin-inline:auto;
  padding:2rem 0; color:var(--ds-accent) }

/* ---- page after page ---- */
.ds-pagination{ margin-top:3rem }
.ds-pagination .nav-links{ display:flex; flex-wrap:wrap; gap:8px;
  align-items:center; justify-content:center }
.ds-pagination .page-numbers{ display:inline-flex; align-items:center;
  justify-content:center; min-width:40px; height:40px; padding:0 12px;
  border:1px solid var(--ds-line); border-radius:var(--ds-field-radius,4px);
  text-decoration:none; font-size:14px }
.ds-pagination .page-numbers:hover{ border-color:var(--ds-link-hover);
  color:var(--ds-link-hover) }
.ds-pagination .page-numbers.current{ background:var(--ds-line);
  color:var(--ds-heading) }
.ds-pagination .dots{ border-color:transparent }

/* ---- the body of a post ----
   Spacing between the pieces of prose, which the browser would otherwise decide
   with margins that have nothing to do with this type scale. */
.ds-post-body > *{ margin:0 0 1.1em }
.ds-post-body > :last-child{ margin-bottom:0 }
.ds-post-body h2,.ds-post-body h3,.ds-post-body h4{ margin:2em 0 .6em }
.ds-post-body ul,.ds-post-body ol{ padding-left:1.3em }
.ds-post-body li{ margin-bottom:.4em }
.ds-post-body img{ border-radius:var(--ds-field-radius,4px) }

/* A quotation set in the editor rather than with the builder's element. */
.ds-post-body blockquote{ margin:2em 0; padding-left:1em;
  border-left:2px solid var(--ds-accent); color:var(--ds-heading) }
.ds-post-body blockquote > :last-child{ margin-bottom:0 }

.ds-post-body pre{ padding:16px; overflow:auto;
  background:color-mix(in srgb, var(--ds-text) 6%, transparent);
  border-radius:var(--ds-field-radius,4px); font-size:14px }
.ds-post-body code{ font-size:.9em }
.ds-post-body figure{ margin:2em 0 }
.ds-post-body figcaption{ margin-top:.6em; font-size:14px; color:var(--ds-accent) }

/* Wide enough to be worth the room, still inside the page. A lead image and a
   full-width figure are the two things prose is allowed to break out for. */
.ds-post-body .alignwide,.ds-post-body .alignfull{
  width:min(100vw - var(--ds-gutter,24px) * 2, var(--ds-max,1200px));
  margin-inline:calc(50% - min(50vw - var(--ds-gutter,24px), var(--ds-max,1200px) / 2)) }

/* ---- tags ---- */
.ds-post-tags{ display:flex; flex-wrap:wrap; gap:8px; margin-top:2.5rem;
  padding-top:1.5rem; border-top:1px solid var(--ds-line) }
.ds-post-tags a{ display:inline-block; padding:4px 12px; font-size:13px;
  text-decoration:none; border:1px solid var(--ds-line);
  border-radius:999px; color:var(--ds-accent) }
.ds-post-tags a:hover{ border-color:var(--ds-link-hover); color:var(--ds-link-hover) }

/* ---- the post before and the post after ---- */
.ds-postnav{ max-width:var(--ds-read,72ch); margin:3rem auto 0;
  padding-top:2rem; border-top:1px solid var(--ds-line) }

/* On a built post it lines up with the rows above it instead.
 *
 * The reading measure was written here too, so Previous and Next stayed in a
 * 72ch column under content that had gone full width - the rule under the last
 * row stopped a third of the way across the page.
 *
 * Width only. No padding: the nav already sits in the same column the rows do
 * and comes out exactly their width, so adding the gutter here applied it a
 * second time and set Previous and Next 50px inside the text above them while
 * the rule over them stayed full width.
 *
 * Selected off the article it follows rather than off a class of its own:
 * the_post_navigation puts its class argument through sanitize_html_class,
 * which strips the space out of two names and welds them into one that matches
 * nothing - which took every rule below off the nav at once. It is the
 * article's sibling, so the question can be asked here instead. */
.ds-post-built ~ .ds-postnav{ max-width:var(--ds-max,1300px) }
.ds-postnav .nav-links{ display:grid; gap:var(--ds-gutter,24px);
  grid-template-columns:repeat(auto-fit,minmax(220px,1fr)) }
.ds-postnav a{ display:flex; flex-direction:column; gap:6px; text-decoration:none }
/* The next post sits on the right and reads from its own edge, so the pair
   point away from each other the way the arrows would. */
.ds-postnav .nav-next{ text-align:right }
.ds-postnav-label{ font-size:13px; letter-spacing:.06em; text-transform:uppercase;
  color:var(--ds-accent) }
/* The title is an H6 and takes H6 whole - size, weight, case, leading and
   tracking - because it is one, rather than a span borrowing one figure off
   a level it was not. It was written as H5's size with 1.25 leading and no
   case at all, so it was the one heading on the page that ignored the
   setting it was copying.

   Only the margin is said here: a heading standing inside a link in a two
   column grid is spaced by the grid, not by the room a heading takes in
   running text. */
.ds-postnav-title{ margin:0 }
.ds-postnav a:hover .ds-postnav-title{ color:var(--ds-link-hover) }

/* ---- comments ---- */
.ds-comments{ max-width:var(--ds-read,72ch); margin:3rem auto 0;
  padding-top:2rem; border-top:1px solid var(--ds-line) }
.ds-comments-title{ margin:0 0 1.5rem; font-size:var(--ds-h3-size);
  line-height:var(--ds-h3-lh,1em) }
/* wp_list_comments draws these with its own walker, so the classes are
   WordPress's rather than ours - styling ds-comment-author and friends would
   have been styling markup this theme never prints. */
.ds-comment-list{ list-style:none; margin:0; padding:0 }
.ds-comment-list .children{ list-style:none; margin:1.5rem 0 0; padding-left:1.5rem;
  border-left:1px solid var(--ds-line) }
.ds-comment-list li{ margin-bottom:1.5rem }
.ds-comment-list .comment-body{ padding-bottom:1.5rem;
  border-bottom:1px solid var(--ds-line) }
.ds-comment-list .children .comment-body:last-child{ border-bottom:0; padding-bottom:0 }

.ds-comment-list .comment-author{ display:flex; align-items:center; gap:10px;
  color:var(--ds-heading) }
.ds-comment-list .comment-author img{ border-radius:50%; flex:0 0 auto }
.ds-comment-list .comment-author .says{ display:none }
.ds-comment-list .comment-meta{ margin:.3rem 0 .8rem; font-size:13px;
  color:var(--ds-accent) }
.ds-comment-list .comment-meta a{ color:inherit; text-decoration:none }
.ds-comment-list .comment-meta a:hover{ text-decoration:underline }
.ds-comment-list .comment-content > :last-child{ margin-bottom:0 }
.ds-comment-list .reply{ margin-top:.6rem; font-size:14px }
.ds-comment-list .comment-awaiting-moderation{ font-size:13px; color:var(--ds-accent) }

.ds-comments-closed{ color:var(--ds-accent) }
.ds-comment-form{ margin-top:2rem }

/* Text for a screen reader and nobody else.
   WordPress prints this class from core, from the templates and from several
   plugins, and it is only a convention - a theme that does not define it shows
   the text. Every card on the blog read "Read more Hello world!", which is the
   accessible label being printed at the visitor.

   Clipped rather than display:none or visibility:hidden: both of those take the
   text out of the accessibility tree as well, which defeats the point of it. */
.screen-reader-text{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); clip-path:inset(50%);
  white-space:nowrap; border:0 }

/* Except when it is focused, so a skip link can be reached by keyboard. */
.screen-reader-text:focus{
  position:static; width:auto; height:auto; margin:0;
  overflow:visible; clip:auto; clip-path:none; white-space:normal }

/* The post header with the title taken out of it, because the title band above
   is already carrying it. Only the meta line is left, so it does not need two
   rems of space under it the way a heading does. */
.ds-post-head-bare{ margin-bottom:1.5rem }

/* A run of prose across the footer, at the body size rather than the small
   print the list blocks use.

   No measure cap. It had one - 72ch, on the reasoning that a paragraph the full
   width of a screen is one nobody finishes a line of - but the block is called
   Full width text and the width it gets is already a decision somebody made in
   the layout field. A block set to three quarters that draws two thirds of that
   is the theme overruling the setting. */
.ds-fb-fulltext{ container-type:inline-size; color:var(--ds-text) }

/* The type spans the block, which is what the block is called.
 *
 * Worked out from the longest line rather than fixed: a line of n characters
 * spans its container at roughly 100/(n * 0.45) of the container width - the
 * factor measured against the theme's own face rather than guessed - so a
 * short line - a wordmark, one sentence - grows to fill the column, while the
 * same block given three paragraphs of prose hits the lower bound and sets at
 * body size instead of shrinking to five pixels.
 *
 * cqi rather than vw, because the block is three quarters of a footer and not
 * three quarters of a screen - measured against the viewport, every column of a
 * footer laid out in quarters would draw at the same size. */
/* Decoration, so it never takes a click.
 *
 * A line box at seven hundred pixels is far taller than the letters in it, and
 * the overspill reaches out of the block into whatever is above - which on a
 * footer laid out in columns is the newsletter field, unclickable behind words
 * that are not even drawn where the cursor is. Links inside it stay clickable:
 * the block is furniture, an anchor in it is not. */
.ds-fb-fit{ pointer-events:none;
  /* Same layer promotion as the builder's own full width text, and for the same
     reason: type this size redrawn on every sub-pixel scroll offset shimmers. */
  transform:translateZ(0); will-change:transform; backface-visibility:hidden }
.ds-fb-fit a{ pointer-events:auto }

.ds-fb-fit{
  /* Everything but the size comes from the Full width text row in Typography.
     The size is the one thing that row cannot set, because it is worked out from
     how long the line is against how wide the block is. */
  font-family:var(--ds-font-fullwidth, var(--ds-font-heading));
  font-weight:var(--ds-fullwidth-weight,400);
  text-transform:var(--ds-fullwidth-case,none);
  letter-spacing:var(--ds-fullwidth-track,-0.02em);
  line-height:var(--ds-fullwidth-lh,1.05em);
  font-size:clamp(
    var(--ds-text-medium-size, var(--ds-p-size,17px)),
    calc(100cqi / (var(--ds-fb-chars,40) * 0.45)),
    /* A ceiling only for the absurd case - a block holding one or two
       characters, where the formula would ask for two hundred percent of the
       column. It is not the size a wordmark settles at; that comes from the
       line length above. Set at 22cqi first, which capped "Darkside" at 169px
       in a 770px block and held it to 84% of the width - the cap doing the
       deciding rather than the text. */
    40cqi
  );
}

/* Prose that never grew keeps a reading line height. The Full width setting is
   for a line set large; on three paragraphs at body size it would be unreadable. */
.ds-fb-fit:has(p + p){
  line-height:var(--ds-text-medium-lh, var(--ds-p-lh,1.5em));
  letter-spacing:var(--ds-text-medium-track,0em);
}
/* Keyed on the fit box, not on the footer block that used to be the only thing
   holding one. As a widget the block arrives without that outer class, so the
   paragraph kept the browser's 1em margin - and 1em of a line set at 492px is
   492px of nothing above it and the same below. It is why a footer with a
   full width text widget in it ended with a screen and a half of empty space. */
.ds-fb-fit p{ margin:0 0 .4em }
.ds-fb-fit p:last-child{ margin-bottom:0 }
.ds-fb-fit p:first-child{ margin-top:0 }


/* ---- the bar above the header ---- */


/* One set of depths, named the same wherever one is chosen.
 *
 * Theme is the figure on General, Layout, Box shadows - so a site that sets a
 * shadow once can point the bar, the title band and anything else at it and
 * they all sit at the same height above the page. */
.ds-sh-soft  { box-shadow:0 6px 24px rgba(0,0,0,.28) }
.ds-sh-medium{ box-shadow:0 10px 34px rgba(0,0,0,.42) }
.ds-sh-strong{ box-shadow:0 16px 48px rgba(0,0,0,.6) }
.ds-sh-theme { box-shadow:var(--ds-shadow,none) }

/* Above whatever follows, or the shadow is drawn under the next band and none
   of it is ever seen. */
.ds-bar[class*="ds-sh-"],
.ds-title[class*="ds-sh-"]{ position:relative; z-index:9 }

/* The header's own vertical align. Only says anything when the bar is taller
   than its contents, which is the moment a height is set on it. */
.ds-header.ds-headv-top > .ds-shell{ align-items:flex-start }
.ds-header.ds-headv-middle > .ds-shell{ align-items:center }
.ds-header.ds-headv-bottom > .ds-shell{ align-items:flex-end }

.ds-bar{
  background:var(--ds-bar-bg);
  color:var(--ds-bar-text);
  border-bottom:var(--ds-bar-line-w) solid var(--ds-bar-line);
  font-size:13px;
  position:relative; z-index:9;
}
/* Whatever is behind the bar, softened.
 *
 * Only where a figure was asked for - the class comes from the plugin, and the
 * declaration does not exist without it. blur(0) is not free: it makes its own
 * compositing layer and repaints on everything that moves underneath, for a
 * result nobody can see.
 *
 * It needs something to blur, so it only shows where the background colour is
 * see-through. On an opaque bar there is nothing behind it to soften and the
 * filter costs the layer for nothing - which is the shop's own decision to
 * make, not one to guess at here. */
.ds-bar-blurs .ds-bar{
  backdrop-filter:blur(var(--ds-bar-blur));
  -webkit-backdrop-filter:blur(var(--ds-bar-blur));
}

.ds-bar a{ color:var(--ds-bar-link); text-decoration:none }
.ds-bar a:hover,.ds-bar a:focus-visible{ color:var(--ds-bar-link-h) }

/* The height is the bar's, and its contents are centered in it rather than
   padded to it - so changing the height moves nothing else. */
.ds-bar-in{
  min-height:var(--ds-bar-h);
  display:flex; align-items:center; gap:16px;
}

/* Two sides, each on its own edge. Both are printed even when one is empty, so
   the other does not slide to the middle when a slot is set to nothing. */
.ds-bar-two .ds-bar-in{ justify-content:space-between }
.ds-bar-side{ display:flex; align-items:center; gap:18px; min-width:0 }
.ds-bar-side.is-right{ margin-left:auto }

.ds-microwidget-menu{ display:flex; align-items:center; gap:18px;
  list-style:none; margin:0; padding:0 }
/* The item is a box, not a line of text.
 *
 * The link inside it is inline-flex, which makes it an inline box sitting on
 * the li's text baseline - and a line box always reserves room under the
 * baseline for descenders, whether or not anything is written there. That is
 * three pixels of nothing under the account links, so the li measured 25.4
 * against a 22.4 line height and the links rode two pixels above the middle of
 * the bar while every other item was centered on it.
 *
 * It reads as padding somebody added. There is no padding: making the li a
 * flex box removes the line box, and with it the space under it. */
.ds-microwidget-menu li{ margin:0; display:flex; align-items:center }

/* A menu pulled from WordPress is set the way the header's own menu is - same
   family, same weight, same case - so the bar reads as part of the site rather
   than as a second navigation somebody styled separately. The size stays the
   bar's own: this is a strip above the header, not the header. */
.ds-microwidget-wpmenu a{
  font-family:var(--ds-menu-font, var(--ds-font-heading));
  font-weight:var(--ds-menu-weight,500);
  text-transform:var(--ds-menu-case,none);
  text-decoration:none }
.ds-microwidget-wpmenu .sub-menu{ display:none }

/* Full width means the bar's contents run to the edges of the screen, not just
   its background - the shell is what holds them in otherwise. */
.ds-bar-w-full > .ds-shell{ max-width:none; width:100% }

/* One column: the whole bar is the message, so it is centered and takes the
   room. */
.ds-bar-one .ds-bar-in{ justify-content:center }
.ds-bar-single{ min-width:0; width:100% }
.ds-bar-one .ds-microwidget-text{ display:block; text-align:center }

/* ---- the marquee ---- */

/* Two copies of the same run, side by side, sliding by exactly one copy's
   width. The second is arriving as the first leaves, so the loop has no gap -
   a single run restarting from nothing shows a hole the width of the screen. */
.ds-microwidget-marquee{ display:flex; width:100%; overflow:hidden; white-space:nowrap }
.ds-microwidget-run{
  flex:0 0 auto; padding-right:var(--ds-marquee-gap,48px);
  /* Its own type, set on Microwidgets, Marquee. Each falls back to what
     the line was set in before the card had these, so a site that never
     opens it sees no change. */
  font-family:var(--ds-marquee-font, inherit);
  font-size:var(--ds-marquee-size, inherit);
  text-transform:var(--ds-marquee-case, none);
  padding-top:var(--ds-marquee-pt, 0);
  padding-bottom:var(--ds-marquee-pb, 0);
  animation:ds-microwidget-slide var(--ds-microwidget-speed,30s) linear infinite;
}
.ds-microwidget-marquee[data-dir="right"] .ds-microwidget-run{ animation-direction:reverse }

@keyframes ds-microwidget-slide{ from{ transform:translateX(0) } to{ transform:translateX(-100%) } }

/* Between one post title and the next. Not a middot - a thin rule reads as a
   divider without being a character in the sentence. */
.ds-microwidget-sep{ display:inline-block; width:1px; height:.9em; margin:0 1.1rem -.1em;
  background:currentColor; opacity:.35 }

@media (prefers-reduced-motion: reduce){
  .ds-microwidget-run{ animation:none }
  .ds-microwidget-marquee{ overflow-x:auto }
  .ds-microwidget-marquee .ds-microwidget-run + .ds-microwidget-run{ display:none }
}

/* ---- how it behaves ---- */

/* Sticks with the header, or leaves and lets the header stick alone. Away is
   the default and costs nothing: the bar simply scrolls off. */
.ds-bar-stick-header{ position:sticky; top:0 }

/* ---- how the two bars behave at each width ----
 *
 * Not here. The widths are a setting now, in General, Layout - and a media
 * query cannot read a custom property, so the whole of both blocks is written
 * out by PHP with the numbers already in it. See DS_Theme::bars_css(). */



/* A mark beside an account link. Sized against the words rather than in pixels,
   so it stays in proportion when the bar's type changes. */
.ds-microwidget-menu a{ display:inline-flex; align-items:center; gap:7px }
.ds-microwidget-mark{ width:1.15em; height:1.15em; flex:0 0 auto }

/* The two sign in columns sit apart on a wide screen and stack on a narrow one,
   which the builder's own row already does - this only stops the second column
   starting hard against the first when they wrap. */
.ds-col .dst-auth{ max-width:none }

/* ------------------------------------------------------------------
   The cart widget

   Drawn by the shop, placed by the theme - top bar, footer block or shortcode.
   Styled here rather than in the shop's own stylesheet, which only loads on
   shop pages: this sits in the top bar of every page, and a stylesheet arriving
   in the footer would show it unstyled first and settle afterwards.

   It carries no position and no colour of its own, so it takes them from
   whatever it has been put inside.
   ------------------------------------------------------------------ */
/* Everything below is set on Microwidgets, Cart, and every one of them falls
   back to what the basket was before that card existed - so a site that never
   opens it sees no change.

   These live here rather than in the shop's own stylesheet for the reason the
   note above gives: that sheet only loads on shop pages, and this sits in the
   header of every page. Written there, the padding, the margin and the colours
   were all set and none of them ever arrived. */
.dst-cart-widget{
  display:inline-flex;
  align-items:center;
  gap:var(--ds-cart-gap,8px);
  padding:var(--ds-cart-pad,0);
  margin:var(--ds-cart-mar,0);
  color:inherit;
  text-decoration:none;
  line-height:1;
}

.dst-cart-mark{ flex:none; color:var(--ds-cart-ink, currentColor) }
.dst-cart-sum{ color:var(--ds-cart-text, currentColor) }

/* Zero is still drawn, so the bar does not change shape the moment somebody
   puts one thing in the basket - and it is drawn exactly as any other figure.

   It used to fade to half at zero. The disc and the number are one element, so
   that took the disc with it: a background colour chosen on Microwidgets was
   only ever seen at full strength once there was something in the basket, and
   an empty one looked switched off. An empty basket is a normal state, not a
   disabled control. */
.dst-cart-count,
.dst-cart-sum{ font-variant-numeric:tabular-nums }

/* The figure, on a disc.

   The disc is only drawn once a background has been chosen - until then this
   is a bare number beside the basket, which is what it always was. At least as
   wide as it is tall whatever the figure is, or 1 is a circle and 12 is an
   oval. */
.dst-cart-count{
  display:inline-flex; align-items:center; justify-content:center;
  min-width:var(--ds-cart-count-size,18px);
  height:var(--ds-cart-count-size,18px);
  padding-inline:calc(var(--ds-cart-count-size,18px) * .22);
  border-radius:999px;
  font-size:calc(var(--ds-cart-count-size,18px) * .62);
  background:var(--ds-cart-count-bg, transparent);
  color:var(--ds-cart-count-ink, var(--ds-cart-text, currentColor));
}

/* ------------------------------------------------------------------
   The sidebar

   The content comes first in the source whichever side the column is shown on,
   so it is reached first by a screen reader and by a crawler. Which side it
   appears on is one grid line.
   ------------------------------------------------------------------ */
.ds-side-grid{
  display:grid;
  grid-template-columns:minmax(0,1fr) var(--ds-side-w,320px);
  gap:var(--ds-side-gap,48px);
  align-items:start;
}

/* Left: the same two columns, read the other way round. The column is moved
   rather than the markup, which is the whole point of ordering it in CSS. */
.ds-side-left .ds-side-grid{ grid-template-columns:var(--ds-side-w,320px) minmax(0,1fr) }
.ds-side-left .ds-side-main{ grid-column:2 }
.ds-side-left .ds-side{ grid-column:1; grid-row:1 }

/* minmax(0,1fr) rather than 1fr on both: a grid track sized 1fr will not shrink
   below the widest thing inside it, so one wide table or one long unbroken
   address pushed the column off the screen instead of scrolling inside itself. */
.ds-side-main{ min-width:0 }

.ds-side{
  min-width:0;
  display:flex;
  flex-direction:column;
  gap:var(--ds-el-gap,40px);
}

/* The sidebar spaces its widgets with a gap, so a widget in there carries no
   margin of its own. Scoped to the sidebar: unscoped it also caught the footer
   widgets, which do space themselves with a bottom margin - and being the later
   rule it won, so the Widgets gap setting did nothing. Side by side in columns
   nobody saw it; stacked on a phone it read as no space at all. */
.ds-side .ds-widget{ margin:0 }

/* WordPress's own search form is a label holding the field, then the button as
   the next block - which stacks. One row, with the field taking what is left. */
.ds-widget .search-form,
.ds-fblockout .search-form{ display:flex; align-items:stretch; gap:8px }
.ds-widget .search-form label,
.ds-fblockout .search-form label{ flex:1 1 auto; min-width:0; display:block; margin:0 }
.ds-widget .search-form .search-field,
.ds-fblockout .search-form .search-field{ width:100%; box-sizing:border-box }
.ds-widget .search-form .search-submit,
.ds-fblockout .search-form .search-submit{ flex:0 0 auto; white-space:nowrap }

/* The same heading treatment the footer widgets get, so a heading does not
   change size depending on which of the two it is standing in. */
.ds-widget-head{
  margin:0 0 .6em;
  font-size:var(--ds-blockhead-size,1rem);
  font-family:var(--ds-blockhead-family,inherit);
  font-weight:var(--ds-blockhead-weight,600);
  letter-spacing:var(--ds-blockhead-track,0);
  text-transform:var(--ds-blockhead-case,none);
}

/* A list of links stacks; a row of marks does not.
   The social list lays itself out and saying display:grid over the top of it
   put five icons in five rows. */
.ds-widget ul{ list-style:none; margin:0; padding:0 }
.ds-widget ul:not(.ds-footer-social):not(.ds-social-inline){ display:grid; gap:8px }
.ds-widget a{ text-decoration:none }
.ds-widget a:hover{ color:var(--ds-link-hover) }

/* One column below the breakpoint, the content first either way - a sidebar
   stacked above the article on a phone is a screen of links before anybody
   reaches what they came for. */
@media (max-width:900px){
  .ds-side-grid,
  .ds-side-left .ds-side-grid{ grid-template-columns:minmax(0,1fr) }
  .ds-side-left .ds-side-main{ grid-column:1 }
  .ds-side-left .ds-side{ grid-column:1; grid-row:auto }
  .ds-side{ margin-top:var(--ds-side-gap,48px) }
}

/* The breadcrumb trail's own colours, set under Page Titles. Blank there means
   inherit, which is the title colour it used to share. */
.ds-crumbs{ color:var(--ds-crumb,inherit) }
.ds-crumbs a{ color:var(--ds-crumb-link,inherit) }

/* The line between the sidebar and the content, on the edge that faces it. Zero
   width draws nothing, which is what a site gets until it asks. */
.ds-side{ background:var(--ds-side-bg,transparent) }

/* The gap is the space between the column and the content, and it stays
   outside the column - the grid already holds it open.
 *
 * It was being added to the padding and pulled back with a negative margin, so
 * the background ran across the gap and the space ended up inside the coloured
 * panel instead of beside it.
 *
 * Padding is the room inside the column, on all four sides. The divider sits on
 * the edge that faces the content. */
.ds-side{ padding:var(--ds-side-pad,0) }

.ds-side-right .ds-side{
  border-left:var(--ds-side-rule-w,0) solid var(--ds-side-rule-color,transparent) }
.ds-side-left .ds-side{
  border-right:var(--ds-side-rule-w,0) solid var(--ds-side-rule-color,transparent) }

@media (max-width:900px){
  .ds-side-right .ds-side, .ds-side-left .ds-side{ border:0 }
}

/* The footer's own widget titles and links, set under Footer, Colors. Blank
   there means inherit, which is the footer's text colour - what they did
   before they had a colour of their own. */
.ds-fb-head{ color:var(--ds-footer-head,inherit) }

/* The words inside a widget, apart from its title - so a footer can carry a
   quieter body under a bright heading without touching the bottom bar. */
/* Inherited, so a widget in the footer is the footer's text colour.

   Two things were taking it away. It read a variable of its own, written by
   a second text swatch on the Footer colours card - that swatch is gone. And
   .ds-widget below sets --ds-side-text, which is the sidebar's colour: a
   widget dropped into a footer came out in whatever the sidebar was set to,
   from a screen with nothing to do with the footer. Named with the footer in
   the selector so it beats that rule on weight rather than on being written
   after it. */
.ds-fblockout,
.ds-footer .ds-widget{ color:inherit }
.ds-fblockout .ds-fb-head,
.ds-footer .ds-widget-head{ color:var(--ds-footer-head,inherit) }
.ds-footer a{ color:var(--ds-footer-link,inherit) }
.ds-footer a:hover{ color:var(--ds-footer-link-hover,inherit) }

/* And the sidebar's, which sit on a different background. */
/* The sidebar's own, named with the sidebar in the selector.

   --ds-side-text and --ds-side-head are set by the Sidebar screen, and these
   two rules were unscoped - so a widget dropped into a footer came out in
   whatever the sidebar was set to, from a screen with nothing to do with
   where it was standing. Anywhere else a widget inherits from what it is in,
   which is what it should always have done. */
.ds-side .ds-widget{ color:var(--ds-side-text,inherit) }
/* A sidebar title follows the block heading unless the Sidebar tab names a
   heading level for it, in which case every one of these carries that level's
   own figure. The margin is written whatever the level, so the gap under a
   title can be set without changing what it is set in. */
.ds-side .ds-widget-head{
  color:var(--ds-side-head,inherit);
  margin-bottom:var(--ds-side-head-mb, .6em);
  font-size:var(--ds-side-head-size, var(--ds-blockhead-size,1rem));
  font-family:var(--ds-side-head-family, var(--ds-blockhead-family,inherit));
  font-weight:var(--ds-side-head-weight, var(--ds-blockhead-weight,600));
  letter-spacing:var(--ds-side-head-track, var(--ds-blockhead-track,0));
  text-transform:var(--ds-side-head-case, var(--ds-blockhead-case,none));
  line-height:var(--ds-side-head-lh, inherit);
}


/* ---- the mark on a button, moving ----
 *
 * Slide: the icon is drawn twice inside a box exactly one icon wide with the
 * overflow cut off, so on hover the first copy leaves to the right while the
 * second arrives from the left and lands where the first one was. The eye reads
 * one arrow travelling through a window rather than an arrow that moved and
 * snapped back - and because it is a transform on one wrapper, leaving the
 * button runs the whole thing backwards for nothing.
 */
.ds-btn-mask{
  display:inline-flex; align-items:center;
  width:var(--ds-btnicon-w,20px); overflow:hidden; flex:none }
.ds-btn-mask .ds-icon{ flex:none; width:var(--ds-btnicon-w,20px) }
.ds-btnmove-slide .ds-btn-mask{
  transition:none }
/* Both copies travel to the right.

   Pulling the first one's left margin negative drags the pair leftwards -
   the first slides out of the left edge and the second arrives from the
   right, which is backwards for an arrow pointing forward. Moving the whole
   strip instead sends the first out to the right and brings the second in
   from the left, which is the direction the arrow is pointing.

   The strip starts shifted one icon left so the copy under the window is the
   second one, and hovering brings it back to nought - so what leaves on the
   right is the copy that was showing. */
.ds-btnmove-slide .ds-btn-mask{ justify-content:flex-start }
.ds-btnmove-slide .ds-btn-mask > .ds-icon:first-child{
  margin-left:calc(var(--ds-btnicon-w,20px) * -1);
  transition:margin-left .42s cubic-bezier(.65,0,.35,1) }
.ds-btnmove-slide:hover .ds-btn-mask > .ds-icon:first-child,
.ds-btnmove-slide:focus-visible .ds-btn-mask > .ds-icon:first-child{
  margin-left:0 }

/* Nudge: the plain version, for a button that only wants a hint of movement. */
.ds-btnmove-nudge .ds-icon{
  transition:transform .28s cubic-bezier(.65,0,.35,1) }
.ds-btnmove-nudge:hover .ds-icon,
.ds-btnmove-nudge:focus-visible .ds-icon{ transform:translateX(4px) }

@media (prefers-reduced-motion: reduce){
  .ds-btnmove-slide .ds-btn-mask > .ds-icon:first-child,
  .ds-btnmove-nudge .ds-icon{ transition:none }
}


/* ---- the close control, last ----
 *
 * The chain reads overlay, then links, then the way out - so the cross arrives
 * once the menu is actually there to be closed rather than at the same moment
 * as the first link. The wait is the links' own fade plus the whole cascade if
 * they are arriving one at a time, worked out from the same two numbers the
 * links use so changing either keeps the order intact.
 *
 * --ds-mlink-count is how many links there are, written on by menu.js: a
 * cascade of five is over five steps sooner than a cascade of forty, and a
 * fixed delay would be too early on one and a wait on the other. */
.ds-panel .ds-close{
  opacity:0;
  /* Nothing to press until it is there.
   *
   * An invisible button is still a button: the cross could be clicked through
   * its whole wait, so a tap in that corner closed a menu that had not finished
   * opening and looked like the overlay had collapsed by itself. The pointer
   * comes back with the opacity, on the same delay. */
  /* visibility, not pointer-events.
   *
   * pointer-events cannot be transitioned, so it flipped the moment its rule
   * started matching - two seconds before the cross faded in, which is exactly
   * the bug it was meant to fix. visibility is transitionable and honours the
   * delay, so the button becomes hittable on the same beat it becomes visible.
   * A hidden element takes no clicks either way. */
  visibility:hidden;
  /* Its own fade, and short. It was taking the links', and a single cross
     easing in over a second after everything else has settled reads as the last
     thing still loading rather than as the way out arriving. The links can be
     as slow as they like; this one lands. */
  transition:opacity .22s ease, visibility .22s }

/* With the panel, not after the links.

   It used to wait out the whole cascade - last index times step, plus the
   link's own fade - which was harmless while the header's burger was the
   real close and this was decoration. The panel owns its close now, and a
   400ms step over nine links is four seconds of open menu with no way out
   of it. The links can take as long as they like; this one is there when
   the panel is. */
body.ds-menu-open .ds-panel .ds-close{
  opacity:1;
  visibility:visible;
  transition-delay:var(--ds-panel-time,.38s) }
body.ds-mlink-none .ds-panel .ds-close{ opacity:1; visibility:visible; transition:none }

/* Closing, it goes first and without waiting - it is the thing that was just
   pressed, and a control that lingers after the menu has begun to leave reads
   as a button that did not work. */
body:not(.ds-menu-open) .ds-panel .ds-close{ transition-delay:0s }

@media (prefers-reduced-motion: reduce){
  .ds-panel .ds-close{ opacity:1; visibility:visible; transition:none }
}


/* ---- the hamburger, left alone ----
 *
 * The panel has a close control of its own now, so the burger turning into a
 * cross behind it is a second way to say the same thing - and on a header that
 * sits under the overlay, one nobody can see anyway. Ticked, every shape the
 * close setting draws is undone for the header's button only: the one in the
 * panel is a different element and keeps its shape.
 *
 * Said against the same [aria-expanded="true"] the morph rules use, so it wins
 * on being later at equal weight rather than on being shouted. */
body.ds-burger-keep .ds-burger[aria-expanded="true"]{ transform:none }
body.ds-burger-keep .ds-burger[aria-expanded="true"] i:nth-child(1),
body.ds-burger-keep .ds-burger[aria-expanded="true"] i:nth-child(2),
body.ds-burger-keep .ds-burger[aria-expanded="true"] i:nth-child(3){
  opacity:1; transform:none; width:24px; height:2px }
body.ds-burger-keep.ds-menuclose-minus .ds-burger[aria-expanded="true"] i:nth-child(1),
body.ds-burger-keep.ds-menuclose-minus .ds-burger[aria-expanded="true"] i:nth-child(3){ opacity:1 }
body.ds-burger-keep.ds-menuclose-word .ds-burger[aria-expanded="true"]::after{ content:none }
body.ds-burger-keep.ds-menuclose-word .ds-burger[aria-expanded="true"] i{ opacity:1 }

/* Two lines and dots keep their own shapes rather than the three the rule above
   hands back - each set its own width, and this only had to undo the morph. */
body.ds-burger-keep .ds-burger-minimal[aria-expanded="true"] i:nth-child(2){ display:none }
body.ds-burger-keep .ds-burger-minimal[aria-expanded="true"] i:nth-child(3){ width:16px }
body.ds-burger-keep .ds-burger-plus[aria-expanded="true"] i:nth-child(2){ width:14px }
body.ds-burger-keep .ds-burger-dots[aria-expanded="true"] i{ width:5px; height:5px; border-radius:50% }

/* ---------------------------------------------------------------------
 * What a post card carries
 *
 * Set on Theme Settings, Elements, Blog post cards. The markup only appears
 * when it has been asked for, so none of this runs on a card that has not.
 * ------------------------------------------------------------------ */

/* The media is the badges' frame, so they can sit on the picture. */
.ds-card-media { position: relative; display: block; }

.ds-card-badges {
  position: absolute;
  top: 10px;
  left: 10px;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  /* Above the picture, and never in the way of the click that opens the
     post - the whole card is the link. */
  pointer-events: none;
  max-width: calc(100% - 20px);
}

.ds-card-badge {
  padding: var(--ds-badge-pad, 4px 10px);
  border-radius: var(--ds-badge-radius, 2px);
  background: var(--ds-badge-bg, var(--ds-accent, #bdfe02));
  color: var(--ds-badge-text, #000);
  font-size: var(--ds-badge-size, 12px);
  line-height: 1.3;
  letter-spacing: .04em;
  white-space: nowrap;
}

/* Tags on a card.
 *
 * Its own class, not the single post's ds-post-tags - that one sits at the
 * foot of an article under a rule, and borrowing it put that rule and two and
 * a half rems of space on every card.
 *
 * Everything here reads a variable so Theme Settings can set it, and falls
 * back to a figure that looks right on a site that has never opened that
 * screen. */
.ds-card-tags {
  margin: 0 0 var(--ds-cardtag-mb, 0px);
  display: flex;
  flex-wrap: wrap;
  gap: 6px 8px;
}

/* The divider, only where it has been asked for. */
.ds-card-tags.has-rule {
  padding-top: 12px;
  border-top: 1px solid var(--ds-cardtag-edge, var(--ds-line, rgba(255,255,255,.16)));
}

.ds-card-tags a {
  display: inline-block;
  padding: 3px 10px;
  font-size: var(--ds-cardtag-size, 12px);
  text-transform: var(--ds-cardtag-case, none);
  text-decoration: none;
  border: 1px solid var(--ds-cardtag-edge, var(--ds-line, rgba(255,255,255,.16)));
  border-radius: var(--ds-cardtag-radius, 999px);
  background: var(--ds-cardtag-bg, transparent);
  color: var(--ds-cardtag-text, var(--ds-quiet, rgba(255,255,255,.7)));
}

.ds-card-tags a:hover,
.ds-card-tags a:focus-visible {
  border-color: var(--ds-link-hover, var(--ds-text, #fff));
  color: var(--ds-link-hover, var(--ds-text, #fff));
}

/* The date, where a card wants it closer to one neighbour than the other. */
.ds-card-body .ds-post-meta { margin-bottom: var(--ds-carddate-mb, 0px) }

/* Read more as a button. The link version keeps whatever it already had;
   this only has to stop the button inheriting the link's underline and
   sitting full width in the card's column. */
/* Read more as a button.
 *
 * The link version of this carries border-bottom and padding-bottom:2px to
 * draw its underline. Adding the button class on top left both in place, so
 * the button had fifteen pixels of padding above the words and two below and
 * the text sat on the floor of it. Both are taken off here. */
.ds-card-more.ds-btn {
  align-self: start;
  width: auto;
  text-decoration: none;
  border-bottom: 0;
  padding-bottom: var(--ds-btn-pady, .85em);
  padding-top: var(--ds-btn-pady, .85em);
}

/* Read more with the underline turned off. Set on Theme Settings, Elements -
   the rule has to name the hover too, or the line comes back the moment the
   pointer touches it. */
.ds-card-more.is-noline,
.ds-card-more.is-noline:hover,
.ds-card-more.is-noline:focus-visible { text-decoration: none; }

/* ---------------------------------------------------------------------
 * Three button sizes
 *
 * One button, at three scales. Colour, corner, border, weight and case all
 * come from the standard button - only the type size and the padding change,
 * which is what keeps the three reading as one family rather than as three
 * different buttons.
 * ------------------------------------------------------------------ */
.ds-btn-sm {
  font-family: var(--ds-btn-sm-font, var(--ds-btn-font, var(--ds-font-text)));
  text-transform: var(--ds-btn-sm-case, var(--ds-btn-case, none));
  font-size: var(--ds-btn-sm-size, 12px);
  padding: var(--ds-btn-sm-pad, 9px 18px 9px 18px);
}

.ds-btn-lg {
  font-family: var(--ds-btn-lg-font, var(--ds-btn-font, var(--ds-font-text)));
  text-transform: var(--ds-btn-lg-case, var(--ds-btn-case, none));
  font-size: var(--ds-btn-lg-size, 17px);
  padding: var(--ds-btn-lg-pad, 18px 34px 18px 34px);
}

/* A magnetised button carries its pull on its own property.
 *
 * translate composes with transform instead of replacing it, so the magnet
 * and any other effect can move the same button at once - which is what stops
 * it shaking while something else animates it. */
.ds-btn.is-magnet,
.ds-mag.is-magnet{
  translate: var(--ds-mag-x, 0px) var(--ds-mag-y, 0px);
}

/* ---------------------------------------------------------------------
 * The bar above the header, holding more than one thing a side
 * ------------------------------------------------------------------ */
.ds-microwidget{ display:inline-flex; align-items:center }
.ds-microwidget + .ds-microwidget{ margin-left:var(--ds-bar-gap, 0) }

.ds-microwidget-phone,
.ds-microwidget-address{ display:inline-flex; align-items:center; gap:.45em; text-decoration:none; color:inherit }
.ds-microwidget-mark{ display:inline-flex; align-items:center; flex:0 0 auto }
.ds-microwidget-mark svg{ display:block }

/* The picture and the markup ones.
 *
 * These shipped with no rules at all, so a picture in a bar sat on the text
 * baseline and reserved a descender under itself - the gap that makes one item
 * in a row of five look a few pixels lower than the rest - and a snippet of
 * markup brought whatever margins its own tags carry into a bar that has no
 * room for them. Both are laid out the way every other microwidget is: a box on
 * the middle of the line, taking no more height than the bar allows. */
/* No height cap. The first version of this capped to --ds-bar-h, which is the
   top bar's height and means nothing in the footer - so a picture in the bottom
   bar was capped to nothing and collapsed to a 50px wide line. The bar sizes
   itself to what it holds; the Width and Height fields on the widget are what
   decide how big the picture is. */
.ds-microwidget-image{
  display:block;
  max-width:100%;
  object-fit:contain;
}

.ds-microwidget-imagelink{ display:inline-flex; align-items:center; flex:0 0 auto; line-height:0 }

.ds-microwidget-html{ display:inline-flex; align-items:center; gap:.45em; min-width:0 }

/* Whatever was pasted in does not get to space itself in a bar. */
.ds-microwidget-html > :first-child{ margin-top:0 }
.ds-microwidget-html > :last-child{ margin-bottom:0 }
.ds-microwidget-html p{ margin:0 }
.ds-microwidget-html img{ display:block; max-width:100% }

/* The microwidgets' icon and text colours.
 *
 * Said against the item rather than against the Text widget alone. Written the
 * narrow way first, these coloured a mark inside a Text item and nothing else -
 * and a Text item is the one kind that draws no mark unless somebody picks one,
 * so an icon colour set on this screen changed nothing anywhere on the site.
 * The marks a bar actually shows belong to the phone, the address and the rest.
 *
 * The two widgets that carry colours of their own keep them: the basket draws
 * .dst-cart-mark and the social marks are links inside their own list, so
 * neither is what these rules name.
 *
 * currentColor as the fallback throughout, so a bar nobody has dressed takes
 * the colour of the bar it sits in exactly as it did - these settings only ever
 * add, they never impose a default.
 *
 * The mark is spaced from the words here rather than by the item, because a
 * Text item may or may not have one and a gap with nothing on one side of it is
 * a gap in the wrong place. */
.ds-microwidget-text,
.ds-microwidget-address,
.ds-microwidget-phone,
.ds-microwidget-menu a{ color:var(--ds-bartext-ink, currentColor) }

.ds-microwidget-text .ds-microwidget-mark,
.ds-microwidget-address .ds-microwidget-mark,
.ds-microwidget-phone .ds-microwidget-mark,
.ds-microwidget-menu a .ds-microwidget-mark{
  color:var(--ds-bartext-icon, var(--ds-icon-ink, currentColor)) }

/* And the drawing inside the mark takes the mark's colour.
 *
 * The phone and the address draw theirs through the shared icon helper, which
 * carries .ds-icon - and .ds-icon takes the site's own icon colour, one class
 * strong, over anything inherited. So the bar's icon colour was set, applied
 * to the mark, and then painted over on the way in: those two icons ignored
 * the setting while the menu's mark, which draws no .ds-icon, obeyed it. The
 * bar's answer wins inside the bar, and falls back to the site's own where the
 * bar has not been given one. */
.ds-microwidget-mark .ds-icon{ color:inherit }

/* Only what can actually be clicked.
 *
 * These named the widgets themselves, and an address is a plain span with no
 * href - so pointing at text that does nothing changed its colour as though it
 * were a link. A phone number is an anchor and a text widget may hold one, so
 * the hover follows the anchor rather than the widget. */
a.ds-microwidget-text:hover,
a.ds-microwidget-address:hover,
a.ds-microwidget-phone:hover,
.ds-microwidget-text a:hover,
.ds-microwidget-address a:hover,
.ds-microwidget-phone a:hover,
.ds-microwidget-menu a:hover{ color:var(--ds-bartext-ink-hover, var(--ds-bartext-ink, currentColor)) }

a.ds-microwidget-text:hover .ds-microwidget-mark,
a.ds-microwidget-address:hover .ds-microwidget-mark,
a.ds-microwidget-phone:hover .ds-microwidget-mark,
.ds-microwidget-text a:hover .ds-microwidget-mark,
.ds-microwidget-address a:hover .ds-microwidget-mark,
.ds-microwidget-phone a:hover .ds-microwidget-mark,
.ds-microwidget-menu a:hover .ds-microwidget-mark{
  color:var(--ds-bartext-icon-hover, var(--ds-bartext-icon, currentColor)) }

.ds-microwidget-text{ display:inline-flex; align-items:center; gap:.45em }

/* What each item does at each width. Set per item, because the thing worth
   dropping first differs - an address is long, a cart is not. */
@media (max-width: 1024px){ .ds-microwidget-off-tablet{ display:none } }
@media (max-width: 640px){ .ds-microwidget-off-phone{ display:none } }

/* A hidden bar takes its height with it.
 *
 * Hiding it was already handled - ds-bar-t-hide and ds-bar-m-hide are set on
 * the bar and dropped at these two widths. What nothing did was stop the bar
 * publishing a height while it was not on the screen.
 *
 * --ds-bar-h is what everything subtracts for the bar: a full screen row
 * working out what is left of the window, a sticky element clearing what is
 * pinned above it, a transparent header placing itself. A bar that is gone and
 * still says it is forty pixels tall leaves that space reserved the whole way
 * down the page, which is the gap above the header on a phone.
 *
 * The breakpoints are the ones the hide rules already use, so the bar and its
 * height always disappear together rather than at two different widths. */
@media (min-width:641px) and (max-width:1024px){
  body:has(.ds-bar-t-hide.ds-bar){ --ds-bar-h:0px }
}
@media (max-width: 640px){
  body:has(.ds-bar-m-hide.ds-bar){ --ds-bar-h:0px }
}

/* ---------------------------------------------------------------------
 * A model behind the footer
 *
 * The same element the page background uses, so it inherits every placement
 * and surface figure from the one renderer. Only where it sits differs: the
 * page's is fixed to the window and this one is held inside the footer, so it
 * scrolls up with it rather than sitting still behind the whole site.
 * ------------------------------------------------------------------ */
.ds-footer{ position:relative }

.ds-footer-scene{
  position:absolute;
  inset:0;
  z-index:0;
  width:100%;
  height:100%;
  pointer-events:none;
  --poster-color:transparent;
}

.ds-footer-scene::part(default-progress-bar){ display:none }

/* The words sit over it. Without this the footer's own content is behind the
   canvas and the scene covers the site's contact details. */
.ds-footer > *:not(.ds-footer-scene){ position:relative; z-index:1 }

/* ---------------------------------------------------------------------
 * What follows the pointer
 *
 * One canvas over everything with pointer events off, so it is scenery and
 * not a surface - nothing it draws can be clicked, and nothing underneath
 * stops working.
 * ------------------------------------------------------------------ */
.ds-cursor{
  position:fixed;
  inset:0;
  z-index:2147483000;
  pointer-events:none;
}

/* Where the site would rather draw its own pointer than let the browser draw
   one as well. */
html.ds-cursor-bare,
html.ds-cursor-bare *{ cursor:none }

/* A text box is the exception: hiding the caret's arrow inside a field makes
   the field feel broken. */
html.ds-cursor-bare input,
html.ds-cursor-bare textarea,
html.ds-cursor-bare select,
html.ds-cursor-bare [contenteditable]{ cursor:auto }

/* A floor for the footer, so a tall model has room to stand in. Only where one
   is asked for - the property is not written at all otherwise. */
.ds-footer{ min-height:var(--ds-footer-min, 0) }

/* ------------------------------------------------------------------
 * Filtering and paging a list of posts
 *
 * The Blog posts element can draw a bar of controls above itself and numbers
 * below - the same row the shop wears over a grid of products, so a blog list
 * and a product list are narrowed and paged the same way.
 * --------------------------------------------------------------- */

.ds-postfilter{
  display:flex;
  flex-wrap:wrap;
  align-items:flex-end;
  gap:var(--ds-field-gap,18px) var(--ds-form-col-gap, var(--ds-gutter,20px));
  margin:0 0 28px;
}

.ds-postfilter-field{
  display:flex;
  flex-direction:column;
  gap:0;
  flex:1 1 160px;
  min-width:0;
}

.ds-postfilter-field > span{
  font-size:12px;
  opacity:.7;
  margin-bottom:var(--ds-label-gap, 10px);
}

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

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

.ds-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;
}

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

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

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

.ds-posts-empty{ opacity:.7 }

/* An HTML block drawn at one heading level.
 *
 * Pasted markup brings whatever tags it was written with, so a specification
 * table headed h2 arrives at the size a page title is set to. Choosing a level
 * on the element draws every heading inside it at that level instead, without
 * anybody having to rewrite the markup - the size, weight, case, line height
 * and tracking all come from the level the site already has in Typography.
 *
 * Said against the tags rather than the block, so a heading keeps being a
 * heading to a screen reader and to a search engine; only its drawing changes.
 */
.ds-html-as-h1 :is(h1,h2,h3,h4,h5,h6){
  font-size:var(--ds-h1-size);
  font-weight:var(--ds-h1-weight);
  text-transform:var(--ds-h1-case);
  line-height:var(--ds-h1-lh);
  letter-spacing:var(--ds-h1-track);
}
.ds-html-as-h2 :is(h1,h2,h3,h4,h5,h6){
  font-size:var(--ds-h2-size);
  font-weight:var(--ds-h2-weight);
  text-transform:var(--ds-h2-case);
  line-height:var(--ds-h2-lh);
  letter-spacing:var(--ds-h2-track);
}
.ds-html-as-h3 :is(h1,h2,h3,h4,h5,h6){
  font-size:var(--ds-h3-size);
  font-weight:var(--ds-h3-weight);
  text-transform:var(--ds-h3-case);
  line-height:var(--ds-h3-lh);
  letter-spacing:var(--ds-h3-track);
}
.ds-html-as-h4 :is(h1,h2,h3,h4,h5,h6){
  font-size:var(--ds-h4-size);
  font-weight:var(--ds-h4-weight);
  text-transform:var(--ds-h4-case);
  line-height:var(--ds-h4-lh);
  letter-spacing:var(--ds-h4-track);
}
.ds-html-as-h5 :is(h1,h2,h3,h4,h5,h6){
  font-size:var(--ds-h5-size);
  font-weight:var(--ds-h5-weight);
  text-transform:var(--ds-h5-case);
  line-height:var(--ds-h5-lh);
  letter-spacing:var(--ds-h5-track);
}
.ds-html-as-h6 :is(h1,h2,h3,h4,h5,h6){
  font-size:var(--ds-h6-size);
  font-weight:var(--ds-h6-weight);
  text-transform:var(--ds-h6-case);
  line-height:var(--ds-h6-lh);
  letter-spacing:var(--ds-h6-track);
}

/* ---------------------------------------------------------------------------
 * The smooth wrapper is not a scroll container
 *
 * ScrollSmoother fixes #smooth-wrapper and hides its overflow, and a fixed box
 * with overflow:hidden is still something the browser can scroll - it simply
 * has no bars. So clicking a link focused it, the browser scrolled that link
 * into view inside the wrapper, and the page lurched to the row that was
 * clicked. Measured on the blog with no scrolling at all: one click set the
 * scrollTop of the wrapper to 1402px.
 *
 * Resetting it afterwards is too late - the frame is already painted. clip is
 * the same visual result and explicitly does NOT create a scroll container, so
 * there is nothing for the browser to scroll and the jump cannot happen.
 *
 * hidden first for anything too old to know clip, where the behaviour is at
 * least no worse than it was.
 * ------------------------------------------------------------------------ */
html.ds-smooth #smooth-wrapper{
  overflow:hidden;
  overflow:clip;
}

/* ---------------------------------------------------------------------------
 * The dropdown list, drawn by the page
 *
 * Chrome hands the highlighted row of a native select to the operating system
 * and ignores CSS, which is why the chosen row took the theme's colour and the
 * hovered one stayed system blue. appearance:base-select is the newer model
 * where the list is real markup, so hover is finally ours.
 *
 * The first attempt at this only set appearance and broke the field: base-select
 * lays a select out as its selected content plus an arrow, so the theme's own
 * padding applied twice and the arrow wrapped onto a second line - 69px tall
 * instead of 45. The field is described here as the row it is, which is what was
 * missing.
 *
 * Behind @supports and last in the file, so a browser without it keeps the
 * native control and nothing earlier can quietly win on source order.
 * ------------------------------------------------------------------------ */
@supports (appearance: base-select) {
  select,
  select::picker(select){ appearance:base-select }

  /* The field: one row, words then arrow, at the height it already had. */
  select{
    display:inline-flex;
    align-items:center;
    gap:.5em;
    line-height:normal;
  }

  /* A select inside its label is block level - the form rules further up say
     so, and a field should fill the width its label gives it.
   *
   * Named here because "label > select" is two selectors deep where "select" is
   * one, and @supports carries no weight of its own: the block form won that
   * tie wherever a select sat under a label, so the row never became a row and
   * the arrow stayed beside the words instead of going to the far edge. Block
   * level flex, so the box behaves exactly as display:block did. */
  label > select{ display:flex }

  select selectedcontent{
    flex:1 1 auto;
    min-width:0;
    overflow:hidden;
    white-space:nowrap;
    text-overflow:ellipsis;
  }

  select::picker-icon{
    flex:none;
    margin-inline-start:auto;
    color:var(--ds-field-text, var(--ds-text));
    transition:transform .18s ease;
  }
  select:open::picker-icon{ transform:rotate(180deg) }

  /* The list itself, as a panel of the page rather than a white sheet. */
  select::picker(select){
    background:var(--ds-opt-bg, var(--ds-bg, #111));
    border:1px solid var(--ds-field-line, var(--ds-line, #2d2d2d));
    border-radius:var(--ds-field-radius, 0);
    padding:0;
    box-shadow:0 10px 30px rgb(0 0 0 / .45);
  }

  select option{ padding:.55em .8em; border:0; box-shadow:none }

  /* The row under the pointer, the row reached by keyboard, and the row already
     chosen - one colour for all three, which is what Forms, Fields, Select,
     Hover background is asking for. */
  select option:hover,
  select option:focus,
  select option:checked{
    background:var(--ds-opt-bg-hover, var(--ds-field-focus, var(--ds-link)));
    color:var(--ds-opt-text-hover, var(--ds-btn-text, var(--ds-bg)));
    box-shadow:none;
  }

  /* The tick this model adds is redundant beside a highlighted row. */
  select option::checkmark{ display:none }
}

/* ---------------------------------------------------------------------------
 * The mobile menu's own logo
 *
 * Drawn above the links when Menu, Show logo is set to Mobile logo. Its size
 * and margin arrive as inline custom properties from the three fields on
 * Branding, so this is one rule however they are set.
 * ------------------------------------------------------------------------- */
.ds-panel-logo{
  position:relative; z-index:2;
  display:flex;
  margin:var(--ds-panel-logo-m, 0);
}

.ds-panel-logo-left{ justify-content:flex-start }
.ds-panel-logo-center{ justify-content:center }

.ds-panel-logo a{ display:block; line-height:0 }

/* Width and height are set where one is given and left alone where it is not,
   so a logo with only a width keeps its own proportions. */
.ds-panel-logo img{
  display:block;
  width:var(--ds-panel-logo-w, auto);
  height:var(--ds-panel-logo-h, auto);
  max-width:100%;
}

/* The two microwidgets along the bottom of the mobile menu. One in each
   corner, with the air above and below set on the Menu screen. */
/* Its own thing at the foot of the panel, not the last row of the menu.

   Pushed to the bottom by the auto margin, and set off by the panel dividers
   rather than joining them - a rule above it says the menu has ended. */
.ds-panel-mw{
  position:relative; z-index:2;
  display:flex; align-items:center; justify-content:space-between; gap:16px;
  margin-top:auto;
  padding-top:18px;
  border-top:1px solid var(--ds-panel-divider, rgb(255 255 255 / .18));
  margin-block:var(--ds-panel-mw-mt, 0) var(--ds-panel-mw-mb, 0);
}

.ds-panel-mw-left{ display:flex; align-items:center; justify-content:flex-start }
.ds-panel-mw-right{ display:flex; align-items:center; justify-content:flex-end }

/* An empty side still holds its corner, so one widget on the right stays on
   the right rather than sliding across to fill the row. */
.ds-panel-mw > div{ flex:1 1 0; min-width:0 }

/* The padding set on the mobile menu logo, inside its own box. */
.ds-panel-logo{ padding:var(--ds-panel-logo-p, 0) }

/* ---------------------------------------------------------------------------
 * The header logo, while the mobile menu is open
 *
 * The header sits above the panel - deliberately, so the close cross is the
 * only cross on screen - which meant the site logo carried on showing over the
 * open menu. With Show logo set to None that was a logo nobody asked for, and
 * with it set to Mobile logo it was a second one beside the panel's own.
 *
 * The panel decides what logo the panel has. The header's steps aside while it
 * is open and comes straight back when it closes.
 * ------------------------------------------------------------------------- */
/* Everything in the header except the way out.

   The header is lifted above the panel deliberately, so its close control can
   be reached - but that lifted the logo, the links, the cart and the account
   marks with it, and they carried on showing over an open menu. The panel is
   meant to be the only thing on the screen. The burger stays, because it is
   the cross that closes it. */
/* The header over an open panel is handled by ds-panel-show-, further up.
   A second rule here said the same thing in a weaker way and only muddied
   which one was in charge. */
