/* ------------------------------------------------------------------
 * simko child theme
 * Loaded from catalog/view/template/common/header.twig, after the core
 * stylesheet, so every rule here wins on equal specificity.
 * ------------------------------------------------------------------ */

:root {
  --simko-brand: #da2229;
  --simko-brand-dark: #b21b21;
  --simko-brand-light: #ef4a50;

  --simko-ink: #1a1a1a;
  --simko-ink-muted: #6b6b6b;

  /* The footer's ground. --simko-ink is the neutral the buttons use; this is
     the same darkness carrying a little of the brand's red, so the band reads
     as part of the palette rather than as the absence of one. */
  --simko-footer: #211b1b;

  --simko-border: #e3e3e3;
  --simko-tint: rgba(218, 34, 41, 0.07);
  --simko-radius: 8px;
  --simko-control-h: 48px;
  --simko-touch: 44px;

  --simko-ease: cubic-bezier(0.4, 0, 0.2, 1);
  --simko-speed: 180ms;
}

/* ------------------------------------------------------------------
 * Links
 *
 * Bootstrap leaves `a` undecorated and underlines it on :hover, so every link
 * the theme has not styled by hand grows an underline under the pointer -- a
 * whole footer column, a breadcrumb, a product name in a list. The colour
 * change is the hover state throughout this theme, so the underline is dropped
 * here once rather than cancelled a few dozen times.
 *
 * This only removes an underline that hover would have added. A link that is
 * underlined at rest -- a link inside a paragraph of prose, where nothing else
 * marks it as one -- keeps its underline: those rules are further down the file
 * and win at equal specificity.
 * ------------------------------------------------------------------ */

a:hover,
a:focus {
  text-decoration: none;
}

/* ------------------------------------------------------------------
 * Preloader (#preloader)
 *
 * Shown only while <html> carries .simko-loading, which simko.js adds from the
 * head and removes on window.load. Display is gated on that class rather than
 * on the element itself, so the markup is inert for a browser that never runs
 * the script and the cover cannot outlive the page load.
 * ------------------------------------------------------------------ */

#preloader {
  display: none;
}

html.simko-loading #preloader,
html.simko-loaded #preloader {
  display: flex;
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  /* Over the drawers (1045) and the lightbox (1080): nothing the shopper opened
     on purpose can be underneath it, because nothing is open yet. */
  z-index: 1090;
  align-items: center;
  justify-content: center;
  background-color: #fff;
  opacity: 1;
  transition: opacity 350ms var(--simko-ease);
}

/* .simko-loading is gone by now, so this is the only rule holding the cover on
   screen -- long enough for the fade, then simko.js removes the element. */
html.simko-loaded #preloader {
  opacity: 0;
  pointer-events: none;
}

/* The page behind the cover must not scroll: a shopper who flicks a covered
   screen would land somewhere down a page they have not seen. */
html.simko-loading,
html.simko-loading body {
  overflow: hidden;
}

.preloader-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.5rem;
  padding: 1.5rem;
}

.preloader-logo {
  width: auto;
  max-width: min(180px, 60vw);
  max-height: 64px;
}

/* Only reached by a store with no logo set, where the header prints the name
   as text too. */
.preloader-wordmark {
  color: var(--simko-brand);
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: 0.01em;
}

/* An indeterminate sweep rather than a spinner: it says the page is coming
   without pretending to know how far along it is, and it is two elements and
   one keyframe instead of a borrowed component. */
.preloader-track {
  position: relative;
  display: block;
  width: min(160px, 50vw);
  height: 2px;
  overflow: hidden;
  border-radius: 2px;
  background-color: var(--simko-border);
}

.preloader-bar {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 40%;
  border-radius: 2px;
  background-color: var(--simko-brand);
  animation: simko-preload 1.15s var(--simko-ease) infinite;
}

@keyframes simko-preload {
  from {
    transform: translateX(-100%);
  }

  to {
    transform: translateX(250%);
  }
}

/* Asked for no motion: the bar states the same thing by sitting still, and the
   cover leaves without a fade. */
@media (prefers-reduced-motion: reduce) {
  .preloader-bar {
    width: 100%;
    animation: none;
    opacity: 0.5;
  }

  html.simko-loading #preloader,
  html.simko-loaded #preloader {
    transition: none;
  }
}

/* ------------------------------------------------------------------
 * Announcement bar (#announcement)
 *
 * A single admin-managed line. Nothing in it is clickable, so the band can stay
 * thin without breaking the 44px touch-target floor -- there is no target.
 * White on #da2229 measures 4.95:1, above the 4.5:1 minimum for body text.
 * ------------------------------------------------------------------ */

#announcement {
  background-color: var(--simko-brand);
  color: #fff;
}

#announcement .announcement-text {
  margin: 0;
  padding: 0.5rem 0;
  min-height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

@media (max-width: 767.98px) {
  #announcement .announcement-text {
    font-size: 0.75rem;
    letter-spacing: 0.02em;
  }
}

/* ------------------------------------------------------------------
 * Header row (<header>)
 *
 * Logo, category menu and the account/cart actions share one baseline. The row
 * wraps, which is what lets the menu drop to its own full-width line below lg
 * without a second markup path.
 * ------------------------------------------------------------------ */

/* Class-scoped, not a bare `header`: every account page heading is a <header>
   too, and it was picking up this band's rule -- its border landed a few pixels
   under the greeting with nothing to separate them. */
header.site-header {
  background-color: #fff;
  border-bottom: 1px solid var(--simko-border);
  margin-bottom: 28px;
  padding: 0;
}

header .header-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 1.25rem;
  min-height: 84px;
}

#logo {
  margin: 0;
  flex: 0 0 auto;
}

#logo img {
  max-width: 150px;
  max-height: 56px;
  width: auto;
  height: auto;
}

#logo h1 {
  margin: 0;
  font-size: 1.5rem;
}

#logo h1 a {
  color: var(--simko-brand);
  text-decoration: none;
}

/* actions cluster */
header .header-actions {
  display: flex;
  align-items: center;
  /* 8px between 44px targets, so a mis-aimed tap lands on nothing rather than on
     the neighbouring control. */
  gap: 0.5rem;
  margin-left: auto;
  flex: 0 0 auto;
}

/* #cart wraps the trigger and the drawer. Core gives it margin-bottom: 10px for
   the old grid column, and a flex row centres the *margin* box, so that 10px
   floated the trigger 5px above the row's centre line. */
#cart {
  display: flex;
  align-items: center;
  margin: 0;
}

/* One rule for every control in the cluster: the search toggle (a <button>), the
   account dropdown trigger (an <a>), wishlist (an <a>) and the cart trigger. */
.header-action,
header .header-action-slot .dropdown > a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-width: var(--simko-touch);
  min-height: var(--simko-touch);
  padding: 0 0.625rem;
  /* Same type as the menu links: the actions are peers of the nav, not a louder
     second tier. */
  color: var(--simko-ink);
  font-size: 0.9375rem;
  font-weight: 400;
  letter-spacing: 0.005em;
  line-height: 1.2;
  text-decoration: none;
  background-color: transparent;
  border: 0;
  border-radius: 6px;
  transition: color var(--simko-speed) var(--simko-ease), background-color var(--simko-speed) var(--simko-ease);
}

/* Colour alone carries the hover state: no fill, and no underline either -- core's
   a:hover re-adds one, which reads as a text link in a row of icon controls. The
   focus ring below is deliberately kept, since a keyboard user has nothing else
   to go on. */
.header-action:hover,
.header-action[aria-expanded="true"],
header .header-action-slot .dropdown > a:hover,
header .header-action-slot .dropdown > a[aria-expanded="true"] {
  color: var(--simko-brand);
  background-color: transparent;
  text-decoration: none;
}

.header-action:focus-visible,
header .header-action-slot .dropdown > a:focus-visible {
  color: var(--simko-brand);
  background-color: transparent;
  text-decoration: none;
  outline: 2px solid var(--simko-brand);
  outline-offset: -2px;
}

.header-action i {
  font-size: 1.0625rem;
  line-height: 1;
}

/* Bootstrap's caret on the account trigger duplicates what the label already
   says, and it is the first thing to crowd the row at narrow widths. */
.header-action.dropdown-toggle::after {
  display: none;
}

/* currency/language ship their own <form> wrapper; collapse it so the dropdown
   sits in the flex row directly. */
header .header-action-slot form {
  margin: 0;
  display: flex;
  align-items: center;
}

header .header-actions .dropdown-menu {
  --bs-dropdown-link-active-bg: var(--simko-brand);
  --bs-dropdown-font-size: 0.875rem;
  margin-top: 0.375rem;
  border: 1px solid var(--simko-border);
  border-radius: var(--simko-radius);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.12);
}

header .header-actions .dropdown-item {
  min-height: 40px;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

header .header-actions .dropdown-item:active {
  background-color: var(--simko-brand);
}

/* cart trigger */
.cart-toggle {
  position: relative;
}

.cart-count {
  position: absolute;
  top: 3px;
  right: 1px;
  box-sizing: border-box;
  min-width: 20px;
  height: 20px;
  padding: 0 0.25rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.6875rem;
  font-weight: 700;
  line-height: 1;
  color: #fff;
  background-color: var(--simko-brand);
  border: 2px solid #fff;
  border-radius: 999px;
}

/* An empty cart still shows its count, but in grey: a red badge reading 0 reads
   as an alert about nothing. */
.cart-count-empty {
  background-color: #9a9a9a;
}

/* ------------------------------------------------------------------
 * Collapsible search panel (#header-search)
 * ------------------------------------------------------------------ */

#header-search .header-search-panel {
  padding: 0 0 1rem;
  max-width: 520px;
  margin-left: auto;
}

header .input-group {
  margin-bottom: 0;
}

header input[name="search"] {
  height: var(--simko-control-h);
  font-size: 0.9375rem;
  padding: 0 1rem;
  color: var(--simko-ink);
  border: 1px solid var(--simko-border);
  border-right: 0;
  border-radius: var(--simko-radius) 0 0 var(--simko-radius);
  box-shadow: none;
  transition: border-color var(--simko-speed) var(--simko-ease);
}

header input[name="search"]::placeholder {
  color: #8a8a8a;
}

header input[name="search"]:focus {
  border-color: var(--simko-brand);
  box-shadow: none;
  outline: 0;
}

/* The submit is the one real CTA in the panel, so it carries the brand. */
header .input-group > button[type="submit"] {
  height: var(--simko-control-h);
  width: 3.25rem;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1rem;
  color: #fff;
  background-color: var(--simko-brand);
  border: 1px solid var(--simko-brand);
  border-radius: 0 var(--simko-radius) var(--simko-radius) 0;
  text-shadow: none;
  transition: background-color var(--simko-speed) var(--simko-ease), border-color var(--simko-speed) var(--simko-ease);
}

header .input-group > button[type="submit"]:hover,
header .input-group > button[type="submit"]:focus-visible {
  color: #fff;
  background-color: var(--simko-brand-dark);
  border-color: var(--simko-brand-dark);
}

header .input-group > button[type="submit"]:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

@media (max-width: 767.98px) {
  #header-search .header-search-panel {
    max-width: none;
  }
}

/* ------------------------------------------------------------------
 * Category menu (#menu)
 *
 * No fill, no rules: bare links, with the brand red spent on the active/hover
 * underline instead of a full-width block.
 * ------------------------------------------------------------------ */

#menu {
  background: none;
  background-color: transparent;
  border: 0;
  border-radius: 0;
  min-height: 0;
  padding: 0;
  margin: 0;
  flex: 1 1 auto;
  min-width: 0;
}

/* At lg and up .offcanvas-lg is an ordinary block and Bootstrap gives its body
   display: flex, so the row has to be told to fill the space #menu was given
   and to centre inside it. Centring the list alone is not enough -- it would
   centre inside a box that had already collapsed to the width of the links. */
@media (min-width: 992px) {
  #menu #menu-drawer {
    flex: 1 1 auto;
    width: 100%;
    min-width: 0;
  }

  #menu #menu-drawer .offcanvas-body {
    flex: 1 1 auto;
    justify-content: center;
    min-width: 0;
  }
}

#menu .navbar-nav {
  flex-wrap: wrap;
  justify-content: center;
}

#menu .navbar-nav > li > a {
  position: relative;
  padding: 0.75rem 0.875rem;
  color: var(--simko-ink);
  font-size: 0.9375rem;
  font-weight: 400;
  letter-spacing: 0.005em;
  text-shadow: none;
  background-color: transparent;
  transition: color var(--simko-speed) var(--simko-ease);
}

/* The underline is a pseudo-element so it can grow from the centre without
   shifting the label or triggering layout. */
#menu .navbar-nav > li > a::after {
  content: "";
  position: absolute;
  left: 0.875rem;
  right: 0.875rem;
  bottom: 0.375rem;
  height: 2px;
  background-color: var(--simko-brand);
  transform: scaleX(0);
  transition: transform var(--simko-speed) var(--simko-ease);
}

#menu .navbar-nav > li > a:hover,
#menu .navbar-nav > li > a:focus-visible,
#menu .navbar-nav > li.show > a,
#menu .navbar-nav > li > a.active,
#menu .navbar-nav > li > a[aria-current] {
  color: var(--simko-brand);
  background-color: transparent;
}

#menu .navbar-nav > li > a:hover::after,
#menu .navbar-nav > li > a:focus-visible::after,
#menu .navbar-nav > li.show > a::after,
#menu .navbar-nav > li > a.active::after,
#menu .navbar-nav > li > a[aria-current]::after {
  transform: scaleX(1);
}

#menu .navbar-nav > li > a:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: -2px;
}

#menu .dropdown-menu {
  border: 1px solid var(--simko-border);
  border-radius: var(--simko-radius);
  box-shadow: 0 12px 32px rgba(0, 0, 0, 0.12);
  margin-top: 0;
  padding: 0.5rem 0;
}

/* Core sizes every column at min-width:200px, which leaves a one-column menu
   padded out far wider than its links. Size to the longest label instead, with
   a ceiling so a stray long name cannot stretch the panel across the header. */
#menu .dropdown-inner ul {
  min-width: 0;
  max-width: 20rem;
}

#menu .dropdown-menu .dropdown-item {
  padding: 0.5rem 1.25rem;
  white-space: nowrap;
}

/* Columns only appear on long lists; keep them apart when they do. */
@media (min-width: 960px) {
  #menu .dropdown-inner {
    gap: 0.5rem;
  }

  /* The last menu item sits closest to the viewport edge, and core only shifts
     multi-column panels left. Anchor it to its own right edge so the panel
     opens inwards whatever its width. */
  #menu .navbar-nav > .nav-item:last-child .dropdown-menu {
    left: auto;
    right: 0;
  }
}

#menu .dropdown-menu .dropdown-item:active,
#menu .dropdown-menu .dropdown-item:focus {
  background-color: var(--simko-brand);
  color: #fff;
}

/* The bar is no longer dark, so the mobile toggler cannot stay white. */
#menu .navbar-toggler {
  border: 0;
  padding: 0.5rem 0.25rem;
  min-width: var(--simko-touch);
  min-height: var(--simko-touch);
}

#menu .navbar-toggler i {
  color: var(--simko-ink);
  border-color: transparent;
}

/* Below lg the menu is a single control -- the toggler, with its list in a
   fixed-position drawer -- so it joins the action cluster on the logo's line
   instead of taking a second full-width line and a divider under it.

   The cluster reads menu, cart, account, search from left to right, which is the
   reverse of source order, so every control is placed by an explicit `order`
   rather than by where it happens to sit in the markup. */
@media (max-width: 991.98px) {
  header .header-bar {
    min-height: 64px;
    padding: 0.625rem 0;
    /* The auto margin on #menu, not a gap, separates the logo from the cluster;
       0 keeps the toggler as tight to the cart as the icons are to each other. */
    gap: 0;
    /* One row is now the only row. Wrapping is what used to move the menu down,
       so leaving it on would drop the whole cluster onto a second line on a
       narrow phone rather than shrinking the logo. */
    flex-wrap: nowrap;
  }

  #logo {
    order: 1;
    /* Lets the logo -- the only elastic item here -- give up width before the
       44px targets have to. */
    min-width: 0;
  }

  #menu {
    order: 2;
    flex: 0 0 auto;
    margin-left: auto;
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
  }

  header .header-actions {
    order: 3;
    /* #menu carries the auto margin for the group now; a second one here would
       open a gap between the toggler and the icons it belongs with. */
    margin-left: 0;
    /* The labels are hidden at this width, so the row is 44px squares with
       nothing but icons in them: at 0.5rem apart they read as separate controls
       scattered across the header. 2px keeps the targets the full 44px -- they
       are still whole squares, only touching -- while the icons group as one
       cluster, and as one cluster with the toggler beside them. */
    gap: 0.125rem;
  }

  #cart {
    order: 1;
  }

  .header-action-account {
    order: 2;
  }

  .header-action-search {
    order: 3;
  }

  /* currency/language render nothing on a single-currency, single-language store.
     When they do appear they take the tail of the reversed row. */
  header .header-action-slot {
    order: 4;
  }

  #menu .navbar-nav {
    justify-content: flex-start;
    width: 100%;
  }

  #menu .navbar-nav > li > a {
    padding: 0.75rem 0;
  }

  #menu .navbar-nav > li > a::after {
    left: 0;
    right: auto;
    bottom: 0.25rem;
    width: 2.5rem;
  }

  #logo img {
    /* 120px, but never wider than the shrunken #logo: a bare max-width in px
       cannot shrink, so on a 320px screen the logo would push the cluster off
       the edge instead of giving way to it. */
    max-width: min(120px, 100%);
    max-height: 44px;
  }

  .header-action,
  header .header-action-slot .dropdown > a {
    padding: 0 0.25rem;
  }
}

/* ------------------------------------------------------------------
 * Category drawer (#menu-drawer)
 *
 * The same panel as the cart: below lg the category list slides in from the
 * left instead of pushing the page down, and at lg and up Bootstrap turns
 * .offcanvas-lg back into the plain row of links the rules further up style.
 *
 * Everything here is inside the breakpoint on purpose. Bootstrap only gives
 * .offcanvas-lg its panel geometry below lg, so a width or a padding declared
 * outside the query would still be in force at desktop -- and would cap the
 * whole category row at the width of a phone drawer.
 * ------------------------------------------------------------------ */

.menu-drawer-title {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--simko-ink);
}

@media (max-width: 991.98px) {
  .menu-drawer {
    /* Narrower than the cart's 400px: these are short labels, and leaving the
       page visible beside them says what the panel is covering. */
    width: min(320px, 85vw);
    border-right: 0;
  }

  #menu-drawer .offcanvas-header {
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--simko-border);
  }

  #menu-drawer .offcanvas-body {
    padding: 0.25rem 1.25rem 1.25rem;
  }

  /* Inside the drawer the list is rows, not a wrapped line of links. Addressed
     by id, because the rules these override are themselves under #menu and
     would otherwise win on specificity whatever their order. */
  #menu-drawer .navbar-nav {
    flex-direction: column;
    align-items: stretch;
    width: 100%;
  }

  #menu-drawer .navbar-nav > li:not(:last-child) {
    border-bottom: 1px solid var(--simko-border);
  }

  #menu-drawer .navbar-nav > li > a {
    padding: 0.875rem 0;
    font-size: 1rem;
  }

  /* The hover underline belongs to a horizontal bar; in a column of rows it
     reads as a stray rule under the label. Childless rows lose it outright, and
     on a parent the same pseudo-element becomes the caret: the theme's
     underline rule and Bootstrap's caret are both ::after on this element, so
     one of the two was always going to be redrawn here. */
  #menu-drawer .navbar-nav > li > a::after {
    display: none;
  }

  #menu-drawer .navbar-nav > li.dropdown > a::after {
    display: inline-block;
    position: static;
    left: auto;
    right: auto;
    bottom: auto;
    width: 0;
    height: 0;
    margin-left: 0.5rem;
    background-color: transparent;
    border-top: 0.3em solid;
    border-right: 0.3em solid transparent;
    border-left: 0.3em solid transparent;
    transform: none;
    transition: transform var(--simko-speed) var(--simko-ease);
  }

  #menu-drawer .navbar-nav > li.dropdown.show > a::after {
    transform: rotate(180deg);
  }

  /* A parent's children open inline -- Bootstrap makes navbar dropdowns static
     below the breakpoint -- so the panel is styled as an indented block of the
     row above it, not as a floating card. */
  #menu-drawer .dropdown-menu {
    border: 0;
    border-radius: 0;
    box-shadow: none;
    padding: 0 0 0.5rem;
  }

  #menu-drawer .dropdown-inner {
    flex-direction: column;
  }

  #menu-drawer .dropdown-menu .dropdown-item {
    padding: 0.5rem 0 0.5rem 1rem;
    white-space: normal;
    color: var(--simko-ink-muted);
  }

  /* The caret sits at the far edge of the row rather than against the label:
     it belongs to the row, which is the whole width of the drawer. */
  #menu-drawer .navbar-nav .dropdown-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
  }
}

/* ------------------------------------------------------------------
 * Cart drawer (#cart-drawer)
 * ------------------------------------------------------------------ */

.cart-drawer {
  width: min(400px, 100vw);
  border-left: 0;
}

.cart-drawer .offcanvas-header {
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--simko-border);
}

.cart-drawer-title {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--simko-ink);
}

.cart-drawer .offcanvas-body {
  padding: 0.5rem 1.25rem;
}

.cart-drawer-items {
  margin: 0;
}

.cart-drawer-item {
  display: flex;
  gap: 0.875rem;
  padding: 1rem 0;
  border-bottom: 1px solid var(--simko-border);
}

.cart-drawer-thumb {
  flex: 0 0 64px;
}

.cart-drawer-thumb img {
  width: 64px;
  height: 64px;
  object-fit: cover;
  border: 1px solid var(--simko-border);
  border-radius: 6px;
}

.cart-drawer-detail {
  flex: 1 1 auto;
  min-width: 0;
}

.cart-drawer-name {
  display: block;
  color: var(--simko-ink);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.35;
  text-decoration: none;
}

.cart-drawer-name:hover {
  color: var(--simko-brand);
}

.cart-drawer-meta {
  margin: 0.25rem 0 0;
  color: var(--simko-ink-muted);
  font-size: 0.75rem;
  line-height: 1.5;
}

.cart-drawer-line {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin-top: 0.5rem;
}

.cart-drawer-line form {
  margin: 0;
}

.cart-drawer-qty {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--simko-ink);
}

/* Destructive, and one tap from checkout, so it stays quiet until aimed at. */
.cart-drawer-remove {
  min-width: var(--simko-touch);
  min-height: var(--simko-touch);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--simko-ink-muted);
  background-color: transparent;
  border: 0;
  border-radius: 6px;
  transition: color var(--simko-speed) var(--simko-ease), background-color var(--simko-speed) var(--simko-ease);
}

.cart-drawer-remove:hover {
  color: var(--simko-brand);
  background-color: var(--simko-tint);
}

.cart-drawer-remove:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: -2px;
}

.cart-drawer-empty {
  margin: 0;
  padding: 3rem 0;
  text-align: center;
  color: var(--simko-ink-muted);
  font-size: 0.9375rem;
}

.cart-drawer-empty i {
  display: block;
  margin-bottom: 0.75rem;
  font-size: 1.75rem;
  color: #cfcfcf;
}

.cart-drawer-footer {
  padding: 1rem 1.25rem 1.25rem;
  border-top: 1px solid var(--simko-border);
  background-color: #fafafa;
}

.cart-drawer-totals {
  margin: 0 0 0.875rem;
  font-size: 0.875rem;
}

.cart-drawer-totals li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.1875rem 0;
  color: var(--simko-ink-muted);
}

.cart-drawer-totals li:last-child {
  margin-top: 0.375rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--simko-border);
  color: var(--simko-ink);
  font-size: 1rem;
  font-weight: 700;
}

.cart-drawer-checkout {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: var(--simko-touch);
  padding: 0 1rem;
  color: #fff;
  background-color: var(--simko-brand);
  border-radius: var(--simko-radius);
  font-size: 0.9375rem;
  font-weight: 600;
  text-decoration: none;
  transition: background-color var(--simko-speed) var(--simko-ease);
}

.cart-drawer-checkout:hover,
.cart-drawer-checkout:focus-visible {
  color: #fff;
  background-color: var(--simko-brand-dark);
}

.cart-drawer-checkout:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

/* ------------------------------------------------------------------
 * Account drawer (#account-drawer)
 *
 * The account links, in the same panel as the cart and off the same edge, at
 * every width -- see the note in header.twig. The dropdown they replace is
 * still what the currency and language pickers use, which is why the
 * .header-action dropdown rules further up stay.
 * ------------------------------------------------------------------ */

.account-drawer {
  /* Narrower than the cart's 400px: this holds five short labels, nothing that
     needs the width. */
  width: min(340px, 100vw);
  border-left: 0;
}

.account-drawer .offcanvas-header {
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--simko-border);
}

.account-drawer-title {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--simko-ink);
}

.account-drawer .offcanvas-body {
  padding: 0.25rem 1.25rem 1.25rem;
}

.account-drawer-links {
  margin: 0;
}

/* Rows, each its own 44px target, rather than the 32px-tall dropdown items the
   links sat in before: this panel is reached by thumb. */
.account-drawer-link {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-height: var(--simko-touch);
  padding: 0.75rem 0;
  color: var(--simko-ink);
  font-size: 0.9375rem;
  font-weight: 500;
  text-decoration: none;
  transition: color var(--simko-speed) var(--simko-ease);
}

.account-drawer-links li:not(:last-child) .account-drawer-link {
  border-bottom: 1px solid var(--simko-border);
}

.account-drawer-link:hover,
.account-drawer-link:focus-visible {
  color: var(--simko-brand);
}

.account-drawer-link:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: -2px;
}

/* Fixed width so the labels line up whatever glyph sits beside them. */
.account-drawer-link i {
  width: 1.25rem;
  flex: 0 0 1.25rem;
  text-align: center;
  font-size: 0.9375rem;
  color: var(--simko-ink-muted);
  transition: color var(--simko-speed) var(--simko-ease);
}

.account-drawer-link:hover i,
.account-drawer-link:focus-visible i {
  color: var(--simko-brand);
}

/* Sign out is not one of the places to go, so it does not read as one. */
.account-drawer-link-out {
  color: var(--simko-ink-muted);
}

/* ------------------------------------------------------------------
 * Homepage sections: the shared heading and the shared scroll-in
 *
 * Both belong to no one section on purpose. A storefront's sections have to
 * arrive the same way and be introduced the same way, or the page reads as
 * separately built blocks stacked on top of each other.
 * ------------------------------------------------------------------ */

.simko-section-title {
  margin: 0 0 2rem;
  text-align: center;
  /* Viewport-relative below the 1.75rem cap, so the longest heading on the
     storefront -- "Choose Your Party Set with us!" -- stays on one line on a
     phone. At 28px it measured ~386px against a 366px content column on a
     390px screen, so it wrapped, and a heading that breaks after "with" reads
     as two thoughts. 6vw holds it inside the column from 320px up; the cap
     takes over at ~467px, which is every tablet and desktop. */
  font-size: clamp(1.125rem, 6vw, 1.75rem);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--simko-ink);
}

/* The bar under the heading. It is what marks where one section starts on a
   page that is otherwise white throughout -- without it two centred headings a
   screen apart read as the same section continuing. */
.simko-section-title::after {
  content: '';
  display: block;
  width: 64px;
  height: 4px;
  margin: 0.9rem auto 0;
  border-radius: 4px;
  background-image: linear-gradient(90deg, var(--simko-brand), #e6a836);
  transition: transform 520ms var(--simko-ease);
}

@media (min-width: 768px) {
  .simko-section-title {
    font-size: 2.25rem;
    margin-bottom: 2.5rem;
  }
}

/* Reveal on scroll.
 *
 * Gated behind .simko-js on <html>, which simko.js sets from the head at parse
 * time. Two reasons it is there and not on the section itself. Content hidden
 * by a stylesheet and never un-hidden is the failure mode of every scroll
 * animation, so with no script -- or under reduced motion, where the script does
 * not set it -- the section is simply on the page from the start. And a section
 * already on screen when the page loads has to be hidden before the first paint
 * or it has nothing to arrive from: hiding it at the same moment it was revealed
 * left the featured carousel, which sits at the top of the homepage, just
 * appearing.
 *
 * The heading goes first and the section's own content follows it, which is the
 * order it is read in. What that content is differs per section, so each one
 * adds its own rule below; this is only the heading and the timing everything
 * else is measured against.
 *
 * It runs once and is over -- nothing here animates on a loop. */
.simko-js .simko-reveal .simko-section-title {
  opacity: 0;
  transform: translateY(20px);
  transition:
    opacity 520ms var(--simko-ease),
    transform 520ms var(--simko-ease);
}

/* The bar draws out from the middle rather than sliding in with the words, so
   the heading lands and is then underlined. */
.simko-js .simko-reveal .simko-section-title::after {
  transform: scaleX(0);
  transition-delay: 260ms;
}

.simko-js .simko-reveal.simko-reveal-in .simko-section-title {
  opacity: 1;
  transform: none;
}

.simko-js .simko-reveal.simko-reveal-in .simko-section-title::after {
  transform: scaleX(1);
}

/* ------------------------------------------------------------------
 * Featured carousel (.party-carousel)
 *
 * Replaces the homepage slideshow. One card is centred and full size; its
 * neighbours are scaled back and faded so the row reads as a single focus with
 * more either side, rather than as four equal tiles.
 *
 * The scale/opacity is plain CSS keyed off Swiper's .swiper-slide-active, not
 * Swiper's coverflow effect: coverflow adds a 3D rotation the design does not
 * call for, and rotated text renders soft on non-retina screens.
 * ------------------------------------------------------------------ */

/* Plain white behind the cards, by request. It carried a soft pink wash for a
   while -- the section runs straight into the category row below it, and the
   wash was what separated them -- but the heading's bar does that job now, and
   with two picture sections stacked the page reads calmer with one ground under
   both. */
.party-carousel {
  position: relative;
  /* No top margin and a shallow top pad below sm: this is the first section on
     the homepage, so its own top spacing stacks on the header's 28px bottom
     margin -- together they were pushing the heading ~96px clear of the header
     on a phone, which reads as an empty screen above the shop. The wider
     spacing is restored from 768px up, where there is room for it. */
  margin: 0 0 2rem;
  padding: 1rem 0 3.5rem;

  /* Weighted to decelerate late, so a card carries speed across most of the
     travel and settles at the end rather than easing out from the halfway
     point. Shared by the row and the cards -- see .swiper-wrapper below. */
  --simko-carousel-ease: cubic-bezier(0.22, 0.61, 0.24, 1);
}

/* Swiper measures the container, so the peek is produced by letting it run the
   full viewport width while the page stays inside .container. */
/* The scene the cards are turned in. Perspective sits on the track rather than
   on each card, so a card's skew depends on where it is across the row -- the
   whole point of the effect -- instead of every card being drawn at an
   identical angle. Matches how Swiper stages its own 3D effects. */
.party-carousel-swiper {
  overflow: hidden;
  /* Shorter than the 1600px it started at: a distant vanishing point flattens
     the turn until the cards read as scaled rectangles rather than angled ones,
     which is the whole depth cue on a white page. */
  perspective: 1150px;
}

/* Swiper slides the row by transforming the wrapper, which would flatten
   everything inside it back into the page without this.
 *
 * The timing function has to be the one the cards use. Swiper sets only a
 * duration on the wrapper and leaves the curve to CSS, so a different curve
 * here means the row travels on one easing while the cards turn on another --
 * they drift apart mid-flight and pull back together at the end, which reads as
 * a stutter even though no frame was dropped. */
.party-carousel-swiper.swiper-initialized .swiper-wrapper {
  transform-style: preserve-3d;
  transition-timing-function: var(--simko-carousel-ease);
}

/* slidesPerView is 'auto', so this width is what decides how much of the
   neighbouring cards shows. It is a share of the container, not the viewport:
   at 390px the container is already down to 360, and anything above ~70% left
   the neighbours as a sliver too thin to read as cards. */
/* How many slides fit is exactly 1 / this width, and the loop depends on that
   number: with five products Swiper needs roughly twice the visible slides to
   wrap around, so the count has to stay under about 2.4 -- and the max-width has
   to sit high enough never to bind. Clamping the slide to a pixel value silently
   raises the count (46% of a 1296px track is 596px; capping that at 520 would
   take it from 2.17 to 2.49) and the loop starts skipping and repeating instead
   of cycling.
 *
 * The widths are also what sizes the middle card. It is drawn at exactly this
 * width and never enlarged past it -- see .swiper-slide-active above -- so the
 * height that makes it stand out over its neighbours is bought here, where it
 * costs nothing in sharpness, rather than with a scale that stretches the card's
 * rastered layer. */
.party-carousel .swiper-slide {
  width: 79%;
  max-width: 680px;
  height: auto;
}

/* Without JS there is no Swiper instance to lay the row out: .swiper-wrapper is
   already a flex row, so this keeps the cards side by side and swipeable
   instead of stacking them full-bleed. */
.party-carousel .swiper-wrapper {
  overflow-x: auto;
  scroll-snap-type: x mandatory;
}

.party-carousel .swiper-initialized .swiper-wrapper {
  overflow-x: visible;
}

.party-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
  padding: 0.5rem;
  text-decoration: none;
  color: var(--simko-ink);
  scroll-snap-align: center;

  /* simko.js paints transform and opacity per frame from each slide's distance
     from the middle, so the values below are only what a card looks like before
     the script runs -- and what it keeps if the script never does. The duration
     is overwritten per move to match whatever Swiper is animating the row with;
     the easing is not, so it stays the one curve for the whole effect. */
  transform: scale(0.7);
  opacity: 0.55;
  transition-property: transform, opacity;
  transition-duration: var(--card-anim, 700ms);
  transition-timing-function: var(--simko-carousel-ease);
  will-change: transform, opacity;
  /* A turned card shows only its front, and letting the GPU skip the reverse
     face keeps the edges from shimmering mid-rotation. */
  backface-visibility: hidden;
}

/* The middle card is shown at its own size and never enlarged. The height that
   makes it stand out comes from the slide widths below; scaling it up instead
   stretched its compositor layer's bitmap and left the settled card soft and
   stepped along every diagonal. */
.swiper-slide-active .party-card {
  transform: none;
  opacity: 1;
}

/* The corner radius lives on the <img> rather than on a clipping container,
   because overflow: hidden here would crop the shadow below along with it. */
.party-card-image {
  position: relative;
  display: block;
  width: 100%;
  border-radius: 16px;
  /* Warm, to match the panel behind it. A neutral grey placeholder reads as a
     cold hole in the section for as long as the image is still loading. */
  background-color: #f6ece8;
}

/* The depth cue that makes the turn legible: on a white page a rotated white
   product photo has almost no silhouette, and the angle simply does not read
   without something grounding the card. Its strength is set per frame from the
   card's distance, so the centre card lifts off the page and the neighbours
   settle back into it.
 *
 * Kept on a pseudo-element with a fixed shadow whose opacity varies, because
 * animating box-shadow itself repaints every frame, while opacity does not. */
.party-card-image::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: 16px;
  box-shadow: 0 26px 50px -18px rgba(26, 26, 26, 0.55), 0 6px 14px -8px rgba(26, 26, 26, 0.3);
  opacity: var(--card-shadow, 0.2);
  transition-property: opacity;
  transition-duration: var(--card-anim, 700ms);
  transition-timing-function: var(--simko-carousel-ease);
}

/* The product images are square and the crop is what the card is selling, so
   the whole frame is shown rather than a height-capped slice of it. Card height
   is kept in range by the slide widths below instead. */
.party-card-image img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: 16px;
}

/* --card-distance is 0 for the centred card and 1 for a full slide away, set
   per frame in simko.js. Riding it lets the label settle up into place as its
   card arrives instead of being dragged across flat with everything else. It is
   a composited transform, so this costs nothing per frame. */
.party-card-name {
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1.2;
  text-align: center;
  transform: translate3d(0, calc(var(--card-distance, 1) * 12px), 0);
  transition: transform var(--card-anim, 700ms) var(--simko-carousel-ease);
}

/* The prompt only belongs to the card that can actually be opened, and only
   once the shopper is pointing at it -- on the neighbours it would be an
   instruction they cannot follow.
 *
 * It keeps its space in the layout while hidden, so revealing it cannot nudge
 * the card. The duration is its own rather than --card-anim: simko.js pins that
 * to 0ms because it repaints the cards itself every frame, and inheriting it
 * would make this snap on instead of fade. */
.party-card-cta {
  font-size: 0.9375rem;
  color: var(--simko-ink-muted);
  text-decoration: underline;
  text-underline-offset: 4px;
  opacity: 0;
  transform: translate3d(0, 8px, 0);
  transition: opacity 260ms var(--simko-ease), transform 260ms var(--simko-ease);
}

/* Where there is no pointer there is no hover to wait for, so the centre card
   simply shows it. */
.swiper-slide-active .party-card-cta {
  opacity: 1;
  transform: none;
}

@media (hover: hover) {
  .swiper-slide-active .party-card-cta {
    opacity: 0;
    transform: translate3d(0, 8px, 0);
  }

  .swiper-slide-active .party-card:hover .party-card-cta,
  .swiper-slide-active .party-card:focus-visible .party-card-cta {
    opacity: 1;
    transform: none;
  }
}

/* A neighbour is scaled to 72% and 45% opaque -- too small a target to open a
   product by accident, and the click is better spent bringing it to the middle,
   which is what slideToClickedSlide does once the link is out of the way. Only
   while the row loops: pinned to its bounds the end cards never reach the
   middle, and this would leave them with no way in. */
.party-carousel-looped .swiper-slide:not(.swiper-slide-active) .party-card {
  pointer-events: none;
}

/* Bootstrap's a:hover outranks the base rule on the card, which would repaint
   the product name in link blue and underline it. Only the call to action
   reacts to hover. */
.party-card:hover,
.party-card:focus-visible {
  color: var(--simko-ink);
  text-decoration: none;
}

.party-card:hover .party-card-cta {
  color: var(--simko-brand);
}

.party-card:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 4px;
  border-radius: var(--simko-radius);
}

/* Arrows sit outside .swiper so the slide overflow cannot clip them. Hidden
   below lg: the gesture is the control on touch, and an arrow there would
   overlap the peeking cards. */
.party-carousel-nav {
  position: absolute;
  top: 50%;
  z-index: 2;
  display: none;
  align-items: center;
  justify-content: center;
  width: var(--simko-touch);
  height: var(--simko-touch);
  margin-top: -1rem;
  padding: 0;
  color: var(--simko-ink);
  background-color: #fff;
  border: 1px solid var(--simko-border);
  border-radius: 50%;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.08);
  transition: color var(--simko-speed) var(--simko-ease), border-color var(--simko-speed) var(--simko-ease), opacity var(--simko-speed) var(--simko-ease);
}

.party-carousel-nav:hover,
.party-carousel-nav:focus-visible {
  color: var(--simko-brand);
  border-color: var(--simko-brand);
}

.party-carousel-nav:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

.party-carousel-nav.swiper-button-disabled {
  opacity: 0.35;
  pointer-events: none;
}

.party-carousel-prev {
  left: 1rem;
}

.party-carousel-next {
  right: 1rem;
}

@media (min-width: 992px) {
  .party-carousel-nav {
    display: flex;
  }
}

/* The arrows stay out of the way until the shopper reaches for the row.
 *
 * Gated on (hover: hover) so it only applies where a pointer can actually
 * reveal them -- on a touch screen there is no hover state to enter, and an
 * arrow that faded out there would simply be gone for good. Focus brings them
 * back for anyone arriving by keyboard, who has no pointer to hover with. */
@media (min-width: 992px) and (hover: hover) {
  .party-carousel-nav {
    opacity: 0;
  }

  .party-carousel:hover .party-carousel-nav,
  .party-carousel:focus-within .party-carousel-nav {
    opacity: 1;
  }
}

/* Swiper leaves the container in place when pagination is switched off; without
   this it would still contribute its margin. */
.party-carousel-pagination:empty {
  display: none;
}

.party-carousel-pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  margin-top: 2rem;
}

/* Swiper's own bullet sizing is inline-styled via CSS variables, so the size
   has to be set through those rather than on the element. */
.party-carousel-pagination .swiper-pagination-bullet {
  width: 8px;
  height: 8px;
  margin: 0;
  background-color: var(--simko-border);
  opacity: 1;
  transition: width var(--simko-speed) var(--simko-ease), background-color var(--simko-speed) var(--simko-ease);
}

.party-carousel-pagination .swiper-pagination-bullet-active {
  width: 24px;
  background-color: var(--simko-brand);
  border-radius: 4px;
}

/* This section's half of the shared reveal: the heading, then the row of cards
   behind it, on the same 140ms offset the category tiles use so the two
   sections arrive at the same pace.
 *
 * The track and the dots are moved, not the whole .party-carousel: the arrows
 * are positioned against the section, and sliding the section would carry them
 * off the cards they page. Opacity and transform also leave layout alone, which
 * matters here -- the track is what Swiper measures itself against, and simko.js
 * runs the reveal after the carousel for the same reason. */
.simko-js .simko-reveal .party-carousel-swiper,
.simko-js .simko-reveal .party-carousel-pagination {
  opacity: 0;
  transform: translateY(28px);
  transition:
    opacity 520ms var(--simko-ease),
    transform 520ms var(--simko-ease);
  transition-delay: 140ms;
}

.simko-js .simko-reveal .party-carousel-pagination {
  transition-delay: 300ms;
}

.simko-js .simko-reveal.simko-reveal-in .party-carousel-swiper,
.simko-js .simko-reveal.simko-reveal-in .party-carousel-pagination {
  opacity: 1;
  transform: none;
}

/* The card stays deliberately wide. Swiper can only loop while it has roughly
   twice the visible slides to draw on, so with a five-product module anything
   narrower than about half the container buys extra cards on screen at the cost
   of the wrap-around -- and without the wrap, paging past the last card leaves
   it stuck off-centre. The big centre card is the point of the layout anyway. */
@media (min-width: 768px) {
  .party-carousel {
    margin: 1.5rem 0 2rem;
    padding: 3.5rem 0 4rem;
  }

  .party-carousel .swiper-slide {
    width: 61%;
  }
}

/* Held at 46%: the loop is what keeps every card reachable dead centre, and
   Swiper drops it once the slides get narrow enough that more than about two
   and a half fit. Anything smaller has to come off the container instead. */
@media (min-width: 1200px) {
  .party-carousel .swiper-slide {
    width: 46%;
  }
}

/* The track deliberately runs the full width of the page container. Capping it
   narrower did shrink the card, but it also pulled the row in from both sides
   and left the neighbours floating in white instead of running off the edge --
   the row read as squeezed rather than as continuing past the screen. */

/* ------------------------------------------------------------------
 * Shop by Category (.category-grid)
 *
 * The top-level categories as picture tiles, sitting under the featured
 * carousel. Where the carousel shows one product at a time, this is the whole
 * range at a glance -- so every tile is the same size, the same shape and the
 * same colour, and nothing is pre-selected for the shopper.
 *
 * Deliberately built from the same parts as the carousel's cards: a 16px
 * radius, the warm placeholder behind the picture, and one neutral shadow. Two
 * sections of pictures stacked on a homepage have to read as one storefront,
 * and a second treatment -- its own radius, its own colour per tile -- read as
 * a different site pasted underneath.
 *
 * A centred flex wrap rather than a CSS grid: with five categories the last row
 * holds two, and a grid would park them under the first two columns. Centring
 * the wrap puts them under the middle of the row above, which is what the
 * design asks for and what reads as deliberate.
 * ------------------------------------------------------------------ */

.category-grid {
  padding: 3rem 0 3.5rem;
}

.category-grid-list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 1.75rem 1.25rem;
}

/* Three per row up to tablet, five across on a desktop -- the widths are set on
   the tile rather than on a grid template so the centred wrap keeps working:
   with five categories the phone and tablet rows come out 3 + 2, and the second
   row sits under the middle of the first rather than against its left edge. */
.category-tile {
  position: relative;
  flex: 0 1 calc((100% - 2.5rem) / 3);
  max-width: 320px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.85rem;
  text-decoration: none;
  color: var(--simko-ink);
}

.category-tile:hover,
.category-tile:focus-visible {
  text-decoration: none;
  color: var(--simko-brand);
}

.category-tile:focus-visible {
  outline: none;
}

/* The picture and everything that reacts to a hover live in the frame, so the
   lift moves the picture and its shadow together while the name below stays on
   its own baseline -- names on the same row must not drift out of line with
   each other.
 *
 * The background colour is only ever seen while the picture loads: the image
 * covers the frame. Warm rather than grey for that reason -- a grey placeholder
 * reads as a cold hole in the row until the picture lands. */
.category-tile-frame {
  position: relative;
  display: block;
  width: 100%;
  aspect-ratio: 1;
  border-radius: 16px;
  background-color: #f6ece8;
  box-shadow: 0 12px 26px -18px rgba(26, 26, 26, 0.55);

  /* One transform, assembled from custom properties, because a hover rule and a
     per-frame script cannot both own the property: the lift and the growth are
     set by the hover, the two angles by simko.js as the pointer moves, and
     neither overwrites the other. Perspective is per tile rather than on the
     row, so a tile turns about its own centre wherever it sits.
   *
   * Short duration on purpose. Anything longer and the turn lags a moving
   * pointer far enough that the tile reads as chasing the cursor rather than
   * as being pushed by it. The curve overshoots slightly and comes back, which
   * is what gives the lift its bit of give rather than a machine's stop. */
  transform:
    perspective(900px)
    rotateX(var(--tile-tilt-x, 0deg))
    rotateY(var(--tile-tilt-y, 0deg))
    translate3d(0, var(--tile-lift, 0px), 0)
    scale(var(--tile-grow, 1));
  transition:
    transform 280ms cubic-bezier(0.34, 1.4, 0.64, 1),
    box-shadow 320ms var(--simko-ease);
}

/* The clip for the hover zoom. It carries the radius and nothing else: a clip
   on the frame itself does not reliably cut a child of its own layer while that
   layer is turned in 3D, and the zoom leaked a sliver of picture over the top
   edge. This span is transformed by nothing. */
.category-tile-clip {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: inherit;
}

.category-tile-image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: scale 520ms var(--simko-ease);
}

.category-tile:hover .category-tile-frame,
.category-tile:focus-visible .category-tile-frame {
  --tile-lift: -8px;
  --tile-grow: 1.02;
  box-shadow: 0 24px 38px -20px rgba(26, 26, 26, 0.6);
}

.category-tile:hover .category-tile-image,
.category-tile:focus-visible .category-tile-image {
  scale: 1.06;
}

.category-tile-name {
  position: relative;
  text-align: center;
  font-size: 1.0625rem;
  font-weight: 700;
  line-height: 1.3;
  transition: color var(--simko-speed) var(--simko-ease);
}

/* Underline grown from the middle out. scaleX on a pseudo-element rather than
   text-decoration, which cannot be animated and would jump in whole. */
.category-tile-name::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -4px;
  height: 2px;
  border-radius: 2px;
  background-color: var(--simko-brand);
  transform: scaleX(0);
  transition: transform 260ms var(--simko-ease);
}

.category-tile:hover .category-tile-name::after,
.category-tile:focus-visible .category-tile-name::after {
  transform: scaleX(1);
}

/* This section's half of the shared reveal (the heading is handled with the
   rest of the shared rules, higher up).
 *
 * The delay is per tile, which is what makes the row arrive in sequence rather
 * than as one block. --tile-index comes from the template, and the 140ms it
 * starts from is the same offset the carousel's track uses, so the two sections
 * arrive the same way. */
.simko-js .simko-reveal .category-tile {
  opacity: 0;
  transform: translateY(28px) scale(0.97);
  transition:
    opacity 520ms var(--simko-ease),
    transform 520ms var(--simko-ease);
  transition-delay: calc(140ms + (var(--tile-index, 0) * 80ms));
}

.simko-js .simko-reveal.simko-reveal-in .category-tile {
  opacity: 1;
  transform: none;
}

@media (min-width: 768px) {
  .category-grid {
    padding: 3.5rem 0 4rem;
  }

  .category-grid-list {
    gap: 2.25rem 2rem;
  }

  .category-tile {
    flex: 0 1 calc((100% - 4rem) / 3);
  }

  .category-tile-name {
    font-size: 1.25rem;
  }
}

/* The whole range on one line. Five across only from lg: at 992px a tile is
   about 170px, which is the point below which the pictures stop being readable
   as scenes and the longer names start wrapping to three lines. */
@media (min-width: 992px) {
  .category-grid-list {
    gap: 2rem 1.25rem;
  }

  .category-tile {
    flex: 0 1 calc((100% - 5rem) / 5);
  }

  .category-tile-name {
    font-size: 1.0625rem;
  }
}

@media (min-width: 1200px) {
  .category-grid-list {
    gap: 2rem 1.75rem;
  }

  .category-tile {
    flex: 0 1 calc((100% - 7rem) / 5);
  }

  .category-tile-name {
    font-size: 1.125rem;
  }
}

/* ------------------------------------------------------------------
 * Product rail (.product-rail)
 *
 * A row of equal product cards that scrolls sideways: one card and a peek of
 * the next on a phone, three at tablet, four across a desktop. The peek is the
 * whole affordance -- a card cut by the right edge is what says the row keeps
 * going, on a touchscreen where there is no arrow to look for.
 *
 * Native scroll with snap points, not a scripted carousel. The featured
 * carousel above needs a script because it paints scale and opacity from a live
 * progress value; a rail only has to stop with a card against the left edge,
 * and the browser does that with the platform's own momentum. The arrows are
 * the one part that needs JS, and they stay hidden until it says the track
 * overflows.
 *
 * Same parts as the two sections above it -- 16px radius, warm placeholder
 * behind the picture, one neutral shadow -- so three picture sections stacked
 * read as one storefront.
 * ------------------------------------------------------------------ */

.product-rail {
  position: relative;
  padding: 3rem 0 3.5rem;

  /* The gap is a variable because the card width is calculated from it: the
     cards have to divide the viewport exactly, gaps included, or four across
     comes out three-and-a-bit. */
  --rail-gap: 1rem;
  --rail-per-view: 1.5;
}

/* The scroller. overscroll-behavior-x keeps a fast horizontal flick inside the
   row instead of handing it to the browser as a back gesture, which on iOS
   navigates away from the page mid-scroll.
 *
 * The scrollbar is hidden but the overflow is not: the row is still scrolled by
 * wheel, trackpad, touch, and by the arrows. A native horizontal bar under a
 * white card row reads as a broken layout on desktop, and no mobile browser
 * paints one anyway. */
.product-rail-viewport {
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  -ms-overflow-style: none;

  /* Room under the cards for their shadow, which an overflow box would
     otherwise cut off square. */
  padding-bottom: 0.75rem;
}

.product-rail-viewport::-webkit-scrollbar {
  display: none;
}

.product-rail-track {
  display: flex;
  gap: var(--rail-gap);
  align-items: stretch;
}

/* Cards do not shrink: the flex basis is the exact share of the viewport that
   leaves --rail-per-view of them showing, and the half in every per-view value
   is what produces the cut card at the right edge.
 *
 * The gap count is one short of the card count because the last card visible is
 * the half one -- 3.5 cards have 3 gaps between them, not 3.5. Written as
 * per-view minus a half for that reason; the values are all x.5 by design. */
.product-rail-card {
  flex: 0 0 calc((100% - (var(--rail-per-view) - 0.5) * var(--rail-gap)) / var(--rail-per-view));
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
  scroll-snap-align: start;
}

/* The picture, its ground and the heart. Position is here rather than on the
   card so the heart sits in the corner of the picture, not of the card's whole
   column -- the name and price underneath are a different height per card. */
.product-rail-frame {
  position: relative;
  border-radius: 16px;
  background-color: #f6ece8;
  box-shadow: 0 12px 26px -18px rgba(26, 26, 26, 0.55);
  transition: box-shadow 320ms var(--simko-ease), transform 280ms var(--simko-ease);
}

.product-rail-image {
  display: block;
  border-radius: inherit;
  overflow: hidden;
}

.product-rail-image img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
}

.product-rail-card:hover .product-rail-frame,
.product-rail-card:focus-within .product-rail-frame {
  transform: translateY(-6px);
  box-shadow: 0 24px 38px -20px rgba(26, 26, 26, 0.6);
}

.product-rail-save {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  margin: 0;
}

/* Full touch target, and a disc behind it: the heart sits on top of whatever
   the product photo happens to be, and a bare glyph on a pale party backdrop is
   invisible. Muted until it is aimed at, so it reads as available rather than
   as already saved. */
.product-rail-heart {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--simko-touch);
  height: var(--simko-touch);
  padding: 0;
  font-size: 1.125rem;
  color: var(--simko-ink-muted);
  background-color: rgba(255, 255, 255, 0.9);
  border: 0;
  border-radius: 50%;
  box-shadow: 0 4px 12px -6px rgba(26, 26, 26, 0.5);
  transition: color var(--simko-speed) var(--simko-ease), transform var(--simko-speed) var(--simko-ease);
}

.product-rail-heart:hover,
.product-rail-heart:focus-visible {
  color: var(--simko-brand);
  transform: scale(1.08);
}

.product-rail-heart:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

.product-rail-heart:active {
  transform: scale(0.94);
}

/* Two lines, then clipped. Product names in this catalogue run long, and a
   third line pushes the price of one card out of line with its neighbours --
   the row stops reading as a row. */
.product-rail-name {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin-top: 0.35rem;
  font-size: 1rem;
  line-height: 1.35;
  color: var(--simko-ink);
  text-decoration: none;
  transition: color var(--simko-speed) var(--simko-ease);
}

.product-rail-name:hover,
.product-rail-name:focus-visible {
  color: var(--simko-brand);
  text-decoration: none;
}

.product-rail-price {
  font-size: 1.0625rem;
  font-weight: 700;
  color: var(--simko-ink);
}

/* Red only when there is something to compare it against: a whole row of red
   prices is a row with no offer in it. */
.product-rail-price-old {
  margin-left: 0.35rem;
  font-size: 0.9375rem;
  font-weight: 400;
  color: var(--simko-ink-muted);
  text-decoration: line-through;
}

.product-rail-price:has(.product-rail-price-old) .product-rail-price-new {
  color: var(--simko-brand);
}

/* Arrows. [hidden] holds until simko.js has measured the track, so a row that
   fits on screen -- four products on a desktop -- never shows a control that
   does nothing. Off the sides of the viewport rather than over the cards: a
   disc floating on a product photo covers the product. */
.product-rail-nav {
  position: absolute;
  top: calc(50% + 1rem);
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  color: var(--simko-ink);
  background-color: #fff;
  border: 1px solid var(--simko-border);
  border-radius: 50%;
  box-shadow: 0 10px 24px -14px rgba(26, 26, 26, 0.65);
  transition: color var(--simko-speed) var(--simko-ease), background-color var(--simko-speed) var(--simko-ease), opacity var(--simko-speed) var(--simko-ease);
}

.product-rail-nav[hidden] {
  display: none;
}

.product-rail-prev {
  left: -0.5rem;
}

.product-rail-next {
  right: -0.5rem;
}

.product-rail-nav:hover {
  color: #fff;
  background-color: var(--simko-brand);
  border-color: var(--simko-brand);
}

.product-rail-nav:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

/* At an end there is nothing that way to go. Dimmed and unclickable rather than
   removed, so the pair does not shift position as the row is scrolled. */
.product-rail-nav:disabled {
  opacity: 0.35;
  pointer-events: none;
}

/* This section's half of the shared reveal. Same 140ms start and 80ms step as
   the category tiles, so the two rows arrive the same way. */
.simko-js .simko-reveal .product-rail-card {
  opacity: 0;
  transform: translateY(28px) scale(0.97);
  transition:
    opacity 520ms var(--simko-ease),
    transform 520ms var(--simko-ease);
  transition-delay: calc(140ms + (var(--card-index, 0) * 80ms));
}

.simko-js .simko-reveal.simko-reveal-in .product-rail-card {
  opacity: 1;
  transform: none;
}

@media (min-width: 576px) {
  .product-rail {
    --rail-per-view: 2.5;
  }
}

/* Three cards and half of a fourth, from tablet all the way up. The half card
   is the point: a row of exactly three fits, and a row that fits gives a
   desktop shopper no reason to think there is more of it. Cut one down the
   middle and the row reads as continuing off the edge. */
@media (min-width: 768px) {
  .product-rail {
    padding: 3.5rem 0 4rem;
    --rail-gap: 1.5rem;
    --rail-per-view: 3.5;
  }

  .product-rail-name {
    font-size: 1.0625rem;
  }

  .product-rail-price {
    font-size: 1.125rem;
  }
}

/* The count stays at three-and-a-half; only the gap opens up. Adding a fourth
   full card here would shrink the pictures past the point where a party set-up
   reads as a scene, and it would take the cut card away with it. */
@media (min-width: 992px) {
  .product-rail {
    --rail-gap: 1.75rem;
  }

  .product-rail-prev {
    left: -1.25rem;
  }

  .product-rail-next {
    right: -1.25rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .header-action,
  header .header-action-slot .dropdown > a,
  #menu .navbar-nav > li > a,
  #menu .navbar-nav > li > a::after,
  .cart-drawer,
  .cart-drawer-remove,
  .cart-drawer-checkout,
  .party-card,
  .party-carousel-nav,
  .party-carousel-pagination .swiper-pagination-bullet,
  .simko-section-title,
  .simko-section-title::after,
  .category-tile-frame,
  .category-tile-image,
  .category-tile-name,
  .category-tile-name::after,
  .product-rail-frame,
  .product-rail-heart,
  .product-rail-name,
  .product-rail-nav {
    transition: none;
  }

  /* The arrows still work; they just jump the row rather than gliding it. */
  .product-rail-viewport {
    scroll-behavior: auto;
  }

  .product-rail-card:hover .product-rail-frame,
  .product-rail-card:focus-within .product-rail-frame,
  .product-rail-heart:hover,
  .product-rail-heart:focus-visible,
  .product-rail-heart:active {
    transform: none;
  }

  /* What a hover means here is the deeper shadow and the colour on the name,
     which stay. What goes is what moves: the lift and the turn. */
  .category-tile-frame,
  .category-tile:hover .category-tile-frame,
  .category-tile:focus-visible .category-tile-frame {
    transform: none;
  }
}

/* ------------------------------------------------------------------
 * Category listing (.category-page)
 *
 * The page behind every link in the main menu, so it inherits the storefront's
 * parts rather than inventing its own: 16px radius on pictures, the warm
 * placeholder behind them, one neutral shadow, brand red reserved for the
 * single action that matters in each block.
 *
 * Three bands above the products -- banner, child-category chips, toolbar --
 * where core had eight rows. Everything below the toolbar is catalogue.
 * ------------------------------------------------------------------ */

.category-page {
  padding-bottom: 3rem;
}

/* Core draws each crumb's separator as a rotated 29px square with two borders,
   which at this size reads as a stray box rather than a chevron. A slash from
   the pseudo-element costs nothing and survives any font size.
 *
 * Keyed off a class the child templates add rather than off the page wrapper,
 * because the trail is the same trail on every listing and on the product page,
 * and two selectors for one component drift apart. */
.simko-crumbs.breadcrumb {
  margin: 1.25rem 0 1.5rem;
  padding: 0;
  font-size: 0.875rem;
  border: 0;
  background: none;
}

.simko-crumbs.breadcrumb > li.breadcrumb-item {
  padding: 0;
  margin: 0;
}

.simko-crumbs.breadcrumb > li.breadcrumb-item::after {
  display: none;
}

.simko-crumbs.breadcrumb > li.breadcrumb-item + li::before {
  content: '/';
  display: inline-block;
  padding: 0 0.55rem;
  color: var(--simko-ink-muted);
}

.simko-crumbs.breadcrumb > li.breadcrumb-item > a {
  color: var(--simko-ink-muted);
  text-decoration: none;
  transition: color var(--simko-speed) var(--simko-ease);
}

.simko-crumbs.breadcrumb > li.breadcrumb-item:last-child > a {
  color: var(--simko-ink);
  font-weight: 600;
}

.simko-crumbs.breadcrumb > li.breadcrumb-item > a:hover,
.simko-crumbs.breadcrumb > li.breadcrumb-item > a:focus-visible {
  color: var(--simko-brand);
}

/* ------------------------------------------------------------------
 * Sidebar category navigation (.simko-catnav)
 * ------------------------------------------------------------------ */

.simko-catnav {
  margin-bottom: 1.75rem;
  padding: 1.25rem;
  background-color: #fff;
  border: 1px solid var(--simko-border);
  border-radius: 16px;
}

.simko-catnav-title {
  margin: 0 0 0.85rem;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--simko-ink-muted);
}

.simko-catnav-list,
.simko-catnav-sub {
  margin: 0;
  padding: 0;
  list-style: none;
}

.simko-catnav-link {
  display: flex;
  align-items: center;
  min-height: var(--simko-touch);
  padding: 0.4rem 0.6rem;
  border-radius: var(--simko-radius);
  color: var(--simko-ink);
  font-size: 0.9375rem;
  text-decoration: none;
  transition:
    color var(--simko-speed) var(--simko-ease),
    background-color var(--simko-speed) var(--simko-ease),
    transform var(--simko-speed) var(--simko-ease);
}

.simko-catnav-link:hover,
.simko-catnav-link:focus-visible {
  color: var(--simko-brand);
  text-decoration: none;
}

.simko-catnav-link:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: -2px;
}

/* The page you are on, marked by weight and colour alone -- no tint behind the
   row, no rule down the left edge. Filled rows turned the list into a stack of
   blocks; red words carry the same information without the weight, and the
   sidebar sits beside a grid of product pictures that every extra mark in it
   has to compete with. */
.simko-catnav-current {
  font-weight: 700;
  color: var(--simko-brand);
}

/* The link slides a few pixels toward its target on hover. Small enough to read
   as the row answering the pointer rather than as the list re-flowing. */
.simko-catnav-link:hover,
.simko-catnav-link:focus-visible {
  transform: translateX(3px);
}

/* Children are indented by the list, not by non-breaking spaces inside the link
   text, so the hierarchy survives being read out. */
.simko-catnav-sub {
  margin-left: 0.6rem;
  padding-left: 0.6rem;
  border-left: 1px solid var(--simko-border);
}

.simko-catnav-child {
  font-size: 0.875rem;
  color: var(--simko-ink-muted);
}

/* This rule sets the muted colour after .simko-catnav-current at equal
   specificity, so a current child took the grey and lost the brand colour. It
   went unnoticed while the tint was there to mark the row; with the tint gone
   the colour is the mark, so restate it. */
.simko-catnav-child.simko-catnav-current {
  color: var(--simko-brand);
}

/* ------------------------------------------------------------------
 * Category banner (.category-hero)
 * ------------------------------------------------------------------ */

.category-hero {
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  margin-bottom: 1.75rem;
  padding: 1.25rem 1.5rem;
  border-radius: 20px;
  /* The tint is the brand at 7%, the same wash the header controls use, so the
     band reads as part of the storefront and not as a coloured advert. */
  background:
    linear-gradient(135deg, var(--simko-tint), rgba(246, 236, 232, 0.85));
}

.category-hero-figure {
  flex: 0 0 auto;
}

.category-hero-image {
  display: block;
  width: 120px;
  height: 120px;
  object-fit: cover;
  border-radius: 16px;
  background-color: #f6ece8;
  box-shadow: 0 12px 26px -18px rgba(26, 26, 26, 0.55);
}

.category-hero-body {
  min-width: 0;
}

/* The red rule under the name is the same mark the homepage section headings
   carry, so a category page reads as the same site one scroll later. It is also
   what keeps the band from looking empty when the category has no picture and
   no description -- which, with the picture off by default, is the usual case. */
.category-hero-title {
  position: relative;
  margin: 0;
  padding-bottom: 0.6rem;
  font-size: 1.75rem;
  font-weight: 800;
  line-height: 1.15;
  color: var(--simko-ink);
}

.category-hero-title::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 56px;
  height: 3px;
  border-radius: 2px;
  background-color: var(--simko-brand);
}

.category-hero-text {
  margin-top: 0.65rem;
  max-width: 62ch;
  color: var(--simko-ink-muted);
  font-size: 0.9375rem;
  line-height: 1.6;
}

.category-hero-text > *:last-child {
  margin-bottom: 0;
}

/* Visually hidden but still focusable and still operable by keyboard: the label
   below is the control a shopper sees, and the ring for it is drawn there. */
.category-hero-toggle {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Off from sm up, where the description is not what costs the products their
   place on the screen and the whole paragraph is simply shown. */
.category-hero-more {
  display: none;
}

@media (min-width: 768px) {
  .category-hero {
    padding: 1.5rem 2rem;
  }

  /* Centring belongs to the picture layout only: on a column of text it centres
     the words too, and a centred H1 over a left-aligned grid of products reads
     as a different page pasted on top. */
  .category-hero-media {
    flex-direction: row;
    align-items: center;
    gap: 1.75rem;
    padding: 2rem;
  }

  .category-hero-image {
    width: 160px;
    height: 160px;
  }

  .category-hero-title {
    font-size: 2.125rem;
  }
}

/* ------------------------------------------------------------------
 * Toolbar (.category-toolbar)
 *
 * The count, the two selects and the grid/list switch on one line. Core spread
 * these across a four-column Bootstrap row and added a full-width primary
 * "Product Compare" CTA -- the loudest control on a page whose job is to sell
 * the products under it. Compare is not rendered here at all now.
 * ------------------------------------------------------------------ */

.category-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1rem;
  margin-bottom: 1.5rem;
  padding: 0.85rem 1rem;
  border: 1px solid var(--simko-border);
  border-radius: 14px;
  background-color: #fff;
}

.category-toolbar-count {
  margin: 0;
  font-size: 0.875rem;
  color: var(--simko-ink-muted);
}

.category-toolbar-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
}

/* The label sits inside the control rather than in a Bootstrap input-group
   addon, which on a phone ate a third of the select's width. */
.category-select {
  display: flex;
  align-items: center;
  gap: 0.4rem;
}

.category-select label {
  margin: 0;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--simko-ink-muted);
  white-space: nowrap;
}

.category-select .form-select {
  min-height: var(--simko-touch);
  width: auto;
  padding: 0.35rem 2rem 0.35rem 0.75rem;
  border: 1px solid var(--simko-border);
  border-radius: var(--simko-radius);
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--simko-ink);
  background-color: #fff;
}

.category-select .form-select:focus {
  border-color: var(--simko-brand);
  box-shadow: 0 0 0 3px var(--simko-tint);
}

.category-view {
  display: flex;
  gap: 0;
  border: 1px solid var(--simko-border);
  border-radius: var(--simko-radius);
  overflow: hidden;
}

.category-view-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--simko-touch);
  height: var(--simko-touch);
  padding: 0;
  border: 0;
  background-color: #fff;
  color: var(--simko-ink-muted);
  transition: color var(--simko-speed) var(--simko-ease), background-color var(--simko-speed) var(--simko-ease);
}

.category-view-btn + .category-view-btn {
  border-left: 1px solid var(--simko-border);
}

.category-view-btn:hover {
  color: var(--simko-brand);
  background-color: var(--simko-tint);
}

.category-view-btn:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: -2px;
}

/* .active is set by core's common.js from the saved preference, so the current
   view is marked by the same class on first paint and after a click. */
.category-view-btn.active {
  color: #fff;
  background-color: var(--simko-brand);
}

/* ------------------------------------------------------------------
 * Below sm: the bands above the products
 *
 * The breadcrumb, the banner and the toolbar together stood about 500px tall on
 * a phone -- a screenful of chrome before the first product card, which is the
 * one thing the page is for. Nothing is removed here: the type comes down, the
 * padding comes in, the description clamps to three lines behind a toggle, and
 * the toolbar's controls share a row instead of stacking into three. That is
 * roughly 170px back, which is most of a card.
 *
 * Scoped to a max-width query rather than folded into the mobile-first base,
 * because the desktop values above are the design and this is the phone making
 * room -- keeping them apart is what makes the compression legible as such.
 * ------------------------------------------------------------------ */

@media (max-width: 767.98px) {
  .simko-crumbs.breadcrumb {
    margin: 0.75rem 0 0.85rem;
    font-size: 0.8125rem;
  }

  .category-hero {
    gap: 1rem;
    margin-bottom: 1rem;
    padding: 1rem 1.125rem;
    border-radius: 16px;
  }

  .category-hero-title {
    padding-bottom: 0.45rem;
    font-size: 1.375rem;
  }

  .category-hero-title::after {
    width: 44px;
  }

  .category-hero-text {
    margin-top: 0.5rem;
    font-size: 0.875rem;
    line-height: 1.5;
    /* -webkit-box is what makes the clamp count lines. It clamps the box, not
       each child, so a description written as several paragraphs still cuts at
       the third line overall. */
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 3;
    line-clamp: 3;
    overflow: hidden;
  }

  .category-hero-toggle:checked ~ .category-hero-text {
    display: block;
    /* Both spellings: the -webkit- one stops mattering the moment display is no
       longer -webkit-box, but the standard property does apply to a block. */
    -webkit-line-clamp: none;
    line-clamp: none;
    overflow: visible;
  }

  .category-hero-more {
    display: inline-flex;
    align-items: center;
    min-height: 1.75rem;
    margin-top: 0.35rem;
    color: var(--simko-brand);
    font-size: 0.8125rem;
    font-weight: 600;
    cursor: pointer;
  }

  /* One label with two words in it; which one shows is the checkbox's state, so
     the control reads as a toggle rather than as a link that disappears. */
  .category-hero-more-close,
  .category-hero-toggle:checked ~ .category-hero-more .category-hero-more-open {
    display: none;
  }

  .category-hero-toggle:checked ~ .category-hero-more .category-hero-more-close {
    display: inline;
  }

  .category-hero-toggle:focus-visible ~ .category-hero-more {
    outline: 2px solid var(--simko-brand);
    outline-offset: 2px;
    border-radius: 4px;
  }

  .category-toolbar {
    gap: 0.5rem 0.75rem;
    margin-bottom: 1rem;
    padding: 0.6rem 0.75rem;
  }

  /* The count takes the first line on its own and the controls share the next.
     Side by side they wrapped into three rows, and of the three the count is
     the one carrying no control at all. */
  .category-toolbar-count {
    flex: 0 0 100%;
    font-size: 0.75rem;
  }

  .category-toolbar-controls {
    gap: 0.5rem;
    min-width: 0;
  }

  .category-select {
    gap: 0.3rem;
    min-width: 0;
  }

  .category-select label {
    font-size: 0.75rem;
  }

  .category-select .form-select {
    min-width: 0;
    padding: 0.35rem 1.6rem 0.35rem 0.5rem;
    font-size: 0.8125rem;
  }
}

/* ------------------------------------------------------------------
 * Product grid (#product-list inside the listing)
 *
 * A CSS grid rather than the Bootstrap row classes on the element: core's
 * common.js rewrites #product-list's entire class attribute on load from the
 * saved grid/list preference, so any class added in the template is gone before
 * the first paint. Grid on the id -- which the script never touches -- keeps the
 * layout, and .product-list (the one class the script does set) switches it to
 * a single column.
 * ------------------------------------------------------------------ */

#product-category #product-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1rem;
  margin: 0;
  --bs-gutter-x: 0;
  --bs-gutter-y: 0;
}

#product-category #product-list > .col {
  width: auto;
  max-width: none;
  padding: 0;
  margin: 0;
  flex: none;
}

@media (min-width: 992px) {
  #product-category #product-list {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1.5rem;
  }
}

@media (min-width: 1400px) {
  #product-category #product-list {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

#product-category #product-list.product-list {
  grid-template-columns: minmax(0, 1fr);
}

/* ------------------------------------------------------------------
 * Listing card (.simko-tile)
 *
 * Rendered by the child theme's product/thumb, so this is the card on every
 * listing: category, search, specials, manufacturer, and the related row on a
 * product page.
 *
 * Same parts as the homepage sections -- 16px radius, warm placeholder, one
 * neutral shadow, lift on hover -- because a shopper arriving from the homepage
 * carousel should land on cards that look like the ones they clicked.
 * ------------------------------------------------------------------ */

.simko-tile {
  height: 100%;
  /* Core's .product-thumb draws a 1px grey box round the whole card. The card
     here is held together by the picture's radius and its shadow instead: a
     border round a white card on a white page adds a line and no information. */
  border: 0;
}

.simko-tile-form {
  display: flex;
  flex-direction: column;
  height: 100%;
  gap: 0.75rem;
}

.simko-tile-frame {
  position: relative;
  border-radius: 16px;
  background-color: #f6ece8;
  box-shadow: 0 12px 26px -18px rgba(26, 26, 26, 0.55);
  transition: box-shadow 320ms var(--simko-ease), transform 280ms var(--simko-ease);
}

.simko-tile-image {
  display: block;
  border-radius: inherit;
  overflow: hidden;
}

/* Square crop, set on the img: the catalogue's thumbnails are square already,
   and declaring the ratio here reserves the space before the file lands, so a
   slow image cannot shove the row it is in down the page. */
.simko-tile-image img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
  transition: scale 520ms var(--simko-ease);
}

.simko-tile:hover .simko-tile-frame,
.simko-tile:focus-within .simko-tile-frame {
  transform: translateY(-6px);
  box-shadow: 0 24px 38px -20px rgba(26, 26, 26, 0.6);
}

.simko-tile:hover .simko-tile-image img,
.simko-tile:focus-within .simko-tile-image img {
  scale: 1.05;
}

/* Reduced from a price on the card because the struck-through price alone is
   easy to miss at this size, and a shopper scanning a grid is reading pictures,
   not numbers. */
.simko-tile-flag {
  position: absolute;
  top: 0.6rem;
  left: 0.6rem;
  padding: 0.25rem 0.6rem;
  border-radius: 999px;
  background-color: var(--simko-brand);
  color: #fff;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* Wishlist and compare, on the picture. Two 44px targets 8px apart, on discs,
   because a bare glyph disappears against a party photograph. Both are quiet
   until aimed at: they are secondary to the buy button below. */
.simko-tile-actions {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.simko-tile-action {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--simko-touch);
  height: var(--simko-touch);
  padding: 0;
  font-size: 1rem;
  color: var(--simko-ink-muted);
  background-color: rgba(255, 255, 255, 0.92);
  border: 0;
  border-radius: 50%;
  box-shadow: 0 4px 12px -6px rgba(26, 26, 26, 0.5);
  transition: color var(--simko-speed) var(--simko-ease), transform var(--simko-speed) var(--simko-ease);
}

.simko-tile-action:hover,
.simko-tile-action:focus-visible {
  color: var(--simko-brand);
  transform: scale(1.08);
}

.simko-tile-action:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

.simko-tile-action:active {
  transform: scale(0.94);
}

/* On a desktop the pair stays out of the photograph until the card is reached
   for. Touch has no hover, so the media query leaves them permanently visible
   there -- a control that only appears on hover is a control a phone never has. */
@media (hover: hover) and (pointer: fine) {
  .simko-tile-actions {
    opacity: 0;
    transform: translateX(6px);
    transition: opacity var(--simko-speed) var(--simko-ease), transform var(--simko-speed) var(--simko-ease);
  }

  .simko-tile:hover .simko-tile-actions,
  .simko-tile:focus-within .simko-tile-actions {
    opacity: 1;
    transform: none;
  }
}

.simko-tile-body {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  gap: 0.35rem;
}

/* Two lines, then clipped: a third line pushes one card's price out of line
   with its neighbours and the row stops reading as a row. */
.simko-tile-name {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.35;
}

.simko-tile-name a {
  color: var(--simko-ink);
  text-decoration: none;
  transition: color var(--simko-speed) var(--simko-ease);
}

.simko-tile-name a:hover,
.simko-tile-name a:focus-visible {
  color: var(--simko-brand);
  text-decoration: none;
}

.simko-tile-rating {
  display: flex;
  gap: 0.1rem;
  font-size: 0.8125rem;
  color: #f0a500;
}

.simko-tile-rating .fa-regular {
  color: var(--simko-border);
}

/* Hidden in the grid: at card width the truncated blurb is a grey block that
   pushes the price and the button below the fold of the card. It comes back in
   list view, where there is a column's width to read it in. */
.simko-tile-text {
  display: none;
  margin: 0;
  color: var(--simko-ink-muted);
  font-size: 0.875rem;
  line-height: 1.55;
}

/* Pushed to the bottom of the card so prices line up across a row whose names
   wrap to different heights. */
.simko-tile-price {
  margin-top: auto;
  padding-top: 0.25rem;
  font-size: 1.0625rem;
  font-weight: 700;
  color: var(--simko-ink);
}

/* Red only when there is something to compare against: a whole row of red
   prices is a row with no offer in it. */
.simko-tile-price-cut {
  color: var(--simko-brand);
}

.simko-tile-price-old {
  margin-left: 0.35rem;
  font-size: 0.9375rem;
  font-weight: 400;
  color: var(--simko-ink-muted);
  text-decoration: line-through;
}

.simko-tile-price-tax {
  display: block;
  font-size: 0.75rem;
  font-weight: 400;
  color: var(--simko-ink-muted);
}

.simko-tile-cart {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.45rem;
  width: 100%;
  min-height: var(--simko-touch);
  margin-top: 0.5rem;
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--simko-brand);
  border-radius: var(--simko-radius);
  background-color: #fff;
  color: var(--simko-brand);
  font-size: 0.9375rem;
  font-weight: 700;
  transition: color var(--simko-speed) var(--simko-ease), background-color var(--simko-speed) var(--simko-ease);
}

/* Outlined at rest, filled on hover: a grid of ten solid red buttons is a grid
   where the pictures come second. */
.simko-tile-cart:hover,
.simko-tile-cart:focus-visible {
  color: #fff;
  background-color: var(--simko-brand);
}

.simko-tile-cart:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

.simko-tile-cart:active {
  background-color: var(--simko-brand-dark);
  border-color: var(--simko-brand-dark);
  color: #fff;
}

.simko-tile-cart:disabled {
  opacity: 0.65;
}

/* Where a failed add lands, on the card that was pressed. Empty on every card
   that has nothing to say, and out of the layout while it is: a reserved line
   under ten buttons is ten gaps. */
.simko-tile-feedback {
  margin: 0.375rem 0 0;
  font-size: 0.75rem;
  line-height: 1.45;
  font-weight: 600;
  color: var(--simko-brand);
}

.simko-tile-feedback:empty {
  display: none;
}

@media (max-width: 575.98px) {
  .simko-tile-cart span {
    font-size: 0.8125rem;
  }
}

/* List view. Picture beside the copy from tablet up, with the description shown
   -- the width is the whole reason to switch to this view. */
@media (min-width: 768px) {
  .product-list .simko-tile-form {
    display: grid;
    grid-template-columns: 220px minmax(0, 1fr);
    gap: 1.5rem;
    align-items: start;
  }

  .product-list .simko-tile-body {
    padding: 0.25rem 0;
  }

  .product-list .simko-tile-text {
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }

  .product-list .simko-tile-name {
    font-size: 1.125rem;
  }

  .product-list .simko-tile-cart {
    width: auto;
    min-width: 200px;
    align-self: flex-start;
  }
}

/* ------------------------------------------------------------------
 * Pagination and empty state
 * ------------------------------------------------------------------ */

.category-pagination,
.product-review-pagination {
  display: flex;
  justify-content: center;
  margin-top: 2rem;
}

.category-pagination .pagination,
.product-review-pagination .pagination {
  gap: 0.35rem;
  margin: 0;
}

.category-pagination .page-link,
.product-review-pagination .page-link {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: var(--simko-touch);
  min-height: var(--simko-touch);
  border: 1px solid var(--simko-border);
  border-radius: var(--simko-radius);
  color: var(--simko-ink);
  font-weight: 600;
}

.category-pagination .page-link:hover,
.product-review-pagination .page-link:hover {
  color: var(--simko-brand);
  background-color: var(--simko-tint);
  border-color: var(--simko-brand);
}

.category-pagination .page-link:focus,
.product-review-pagination .page-link:focus {
  box-shadow: 0 0 0 3px var(--simko-tint);
}

.category-pagination .page-item.active .page-link,
.product-review-pagination .page-item.active .page-link {
  color: #fff;
  background-color: var(--simko-brand);
  border-color: var(--simko-brand);
}

.category-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  padding: 4rem 1.5rem;
  text-align: center;
  border: 1px solid var(--simko-border);
  border-radius: 20px;
  background-color: #fff;
}

.category-empty i {
  font-size: 2.5rem;
  color: var(--simko-ink-muted);
}

.category-empty p {
  margin: 0;
  color: var(--simko-ink-muted);
}

.category-empty-btn {
  display: inline-flex;
  align-items: center;
  min-height: var(--simko-touch);
  padding: 0.5rem 1.5rem;
  border-radius: var(--simko-radius);
  background-color: var(--simko-brand);
  color: #fff;
  font-weight: 700;
  text-decoration: none;
  transition: background-color var(--simko-speed) var(--simko-ease);
}

.category-empty-btn:hover,
.category-empty-btn:focus-visible {
  background-color: var(--simko-brand-dark);
  color: #fff;
  text-decoration: none;
}

.category-empty-btn:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .simko-catnav-link,
  .category-view-btn,
  .simko-tile-frame,
  .simko-tile-image img,
  .simko-tile-actions,
  .simko-tile-action,
  .simko-tile-name a,
  .simko-tile-cart,
  .category-empty-btn {
    transition: none;
  }

  /* What a hover means on a card here is the deeper shadow and the red on the
     name, which stay. What goes is what moves. */
  .simko-tile:hover .simko-tile-frame,
  .simko-tile:focus-within .simko-tile-frame,
  .simko-tile-action:hover,
  .simko-tile-action:focus-visible,
  .simko-tile-action:active {
    transform: none;
  }

  .simko-tile:hover .simko-tile-image img,
  .simko-tile:focus-within .simko-tile-image img {
    scale: 1;
  }
}

/* ------------------------------------------------------------------
 * Category listing: arrival and hover polish
 *
 * Same machinery as the homepage sections: simko.js adds .simko-js at parse
 * time (only with an IntersectionObserver present and reduced motion not asked
 * for) and .simko-reveal-in as each block is scrolled to. Everything hidden
 * here is therefore hidden only where something is guaranteed to un-hide it.
 *
 * Order on arrival is the order the page is read in: sidebar and banner, then
 * the toolbar, then the grid card by card. The delays are small -- 520ms total
 * for a block, 70ms between cards -- because this is a page a shopper came to
 * in order to buy from, not an intro to sit through.
 * ------------------------------------------------------------------ */

.simko-js .category-hero.simko-reveal,
.simko-js .category-toolbar.simko-reveal,
.simko-js .simko-catnav.simko-reveal {
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity 520ms var(--simko-ease),
    transform 520ms var(--simko-ease);
}

/* The toolbar follows the banner rather than arriving beside it, so the two
   bands read as a sequence down the page. */
.simko-js .category-toolbar.simko-reveal {
  transition-delay: 80ms;
}

.simko-js .category-hero.simko-reveal-in,
.simko-js .category-toolbar.simko-reveal-in,
.simko-js .simko-catnav.simko-reveal-in {
  opacity: 1;
  transform: none;
}

/* The rule under the category name draws out from the left after the band has
   settled -- the same mark, drawn the same way, as the homepage headings. */
.simko-js .category-hero.simko-reveal .category-hero-title::after {
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 420ms var(--simko-ease) 200ms;
}

.simko-js .category-hero.simko-reveal-in .category-hero-title::after {
  transform: scaleX(1);
}

/* The sidebar's links arrive in sequence behind their own heading. Indexed by
   nth-child rather than a template variable: the module's markup is core's
   shape and the list is short enough that six steps cover it. */
.simko-js .simko-catnav.simko-reveal .simko-catnav-item {
  opacity: 0;
  transform: translateX(-10px);
  transition:
    opacity 420ms var(--simko-ease),
    transform 420ms var(--simko-ease);
}

.simko-js .simko-catnav.simko-reveal-in .simko-catnav-item {
  opacity: 1;
  transform: none;
}

.simko-js .simko-catnav.simko-reveal-in .simko-catnav-item:nth-child(1) { transition-delay: 60ms; }
.simko-js .simko-catnav.simko-reveal-in .simko-catnav-item:nth-child(2) { transition-delay: 120ms; }
.simko-js .simko-catnav.simko-reveal-in .simko-catnav-item:nth-child(3) { transition-delay: 180ms; }
.simko-js .simko-catnav.simko-reveal-in .simko-catnav-item:nth-child(4) { transition-delay: 240ms; }
.simko-js .simko-catnav.simko-reveal-in .simko-catnav-item:nth-child(5) { transition-delay: 300ms; }
.simko-js .simko-catnav.simko-reveal-in .simko-catnav-item:nth-child(n+6) { transition-delay: 360ms; }

/* The grid. --card-index comes from the template, so the stagger follows the
   sort order however many products the page is showing. Capped by the 10-per-
   page default: at 70ms a step the last card of a page of ten starts 630ms in,
   which is still inside the time it takes to look at the first row. */
.simko-js .category-products.simko-reveal .simko-tile {
  opacity: 0;
  transform: translateY(26px) scale(0.97);
  transition:
    opacity 480ms var(--simko-ease),
    transform 480ms var(--simko-ease);
  transition-delay: calc(120ms + (var(--card-index, 0) * 70ms));
}

.simko-js .category-products.simko-reveal-in .simko-tile {
  opacity: 1;
  transform: none;
}

/* A light sweep across the photograph when a card is hovered. One pass, on
   entry only, so it reads as the card catching the light rather than as
   something looping for attention. Painted above the picture and below the
   badge and the two action buttons, and deaf to the pointer so it cannot eat a
   click meant for the product. */
.simko-tile-image {
  position: relative;
}

.simko-tile-image::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(115deg, rgba(255, 255, 255, 0) 38%, rgba(255, 255, 255, 0.5) 50%, rgba(255, 255, 255, 0) 62%);
}

.simko-tile:hover .simko-tile-image::after,
.simko-tile:focus-within .simko-tile-image::after {
  animation: simko-tile-sheen 760ms var(--simko-ease);
}

@keyframes simko-tile-sheen {
  from {
    opacity: 1;
    transform: translateX(-110%);
  }

  to {
    opacity: 1;
    transform: translateX(110%);
  }
}

/* The bag leans toward the cart the button is about to add to. */
.simko-tile-cart i {
  transition: transform var(--simko-speed) var(--simko-ease);
}

.simko-tile-cart:hover i,
.simko-tile-cart:focus-visible i {
  transform: translateX(-2px) scale(1.08);
}

@media (prefers-reduced-motion: reduce) {
  /* The sheen is motion and nothing else, so it goes entirely. The bag keeps
     its place on the button; only its nudge stops. */
  .simko-tile-image::after {
    display: none;
  }

  .simko-tile-cart i {
    transition: none;
  }

  .simko-tile-cart:hover i,
  .simko-tile-cart:focus-visible i {
    transform: none;
  }

  .simko-catnav-link:hover,
  .simko-catnav-link:focus-visible {
    transform: none;
  }
}

/* The category list follows the page down. The grid beside it is ten products
   deep at the default page size, and a shopper who has scrolled to the bottom
   of it should not have to scroll back up to change category.
 *
 * Only from md, which is where the sidebar exists at all -- below that the
 * aside is display:none and the main menu carries the same links.
 *
 * No max-height and no inner scroll on the column: capping it and letting it
 * scroll cut the card in half on a short laptop viewport, and this store's
 * top-level list is five entries. A catalogue whose sidebar runs taller than
 * the viewport would want that cap back. */
@media (min-width: 768px) {
  .category-page #column-left {
    position: sticky;
    top: 1.5rem;
    /* Sticky on the column, not on the card inside it, and the column has to
       stop stretching first: as a stretched flex item its own box already runs
       the height of the row, so there is nothing left for the card inside to
       travel through and it comes unpinned as soon as the grid's last row is
       reached. Held to its content height, the column is what travels, and its
       containing block is the row -- which is exactly as tall as the listing. */
    align-self: flex-start;
  }
}

/* ------------------------------------------------------------------
 * Product page (.product-page)
 *
 * Built to the supplied mobile design: one swipeable gallery running the full
 * width of the phone, then a block holding the name, the identifier and the
 * price with the quantity stepper beside it, then a single black pill for the
 * buy. Everything a shopper needs to decide and to act is on the first screen.
 *
 * From lg it becomes two columns -- gallery left and sticky, panel right -- and
 * from there the picture stays on screen for the whole length of the page.
 *
 * The parts are the storefront's own: 16px radius on pictures, the warm
 * placeholder behind them, one neutral shadow, brand red on the price and
 * nowhere else. The buy is the exception and it is deliberate: the design puts
 * it in black, which on a page whose price is already red is the only way for
 * the button to be the loudest thing without two reds competing.
 * ------------------------------------------------------------------ */

.product-page {
  padding-bottom: 3rem;
}

.product-main {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  margin-bottom: 2.5rem;
}

/* ------------------------------------------------------------------
 * Gallery (.product-gallery)
 * ------------------------------------------------------------------ */

.product-gallery {
  min-width: 0;
}

/* Full width of the screen on a phone, as drawn. The inset being undone is the
   .col padding inside a .row inside .container, which nets out to the
   container's own 0.75rem -- the product layout carries no side column, so
   there is nothing beside the gallery for it to run into.
 *
 * From sm the picture becomes a card again: at tablet width and up a
 * photograph bleeding off both edges of a page whose every other picture is a
 * 16px-radius card reads as a different site. */
.product-gallery-stage {
  position: relative;
  margin-inline: -0.75rem;
  background-color: #f6ece8;
}

.product-gallery-swiper {
  overflow: hidden;
}

/* Without Swiper the wrapper is still a flex row, so this keeps the pictures
   side by side and swipeable rather than stacking them full-bleed. */
.product-gallery-swiper .swiper-wrapper {
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}

.product-gallery-swiper .swiper-wrapper::-webkit-scrollbar {
  display: none;
}

.product-gallery-swiper.swiper-initialized .swiper-wrapper {
  overflow-x: visible;
}

.product-gallery-swiper .swiper-slide {
  flex: 0 0 100%;
  width: 100%;
  scroll-snap-align: center;
}

/* The slide is a button because it opens the lightbox, so every button style
   the browser and Bootstrap would give it has to come off first. */
.product-gallery-slide {
  position: relative;
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
  overflow: hidden;
}

/* Square, and declared on the element so the space is reserved before the file
   lands -- a slow picture must not shove the name and the price down the page
   after the shopper has started reading them. */
.product-gallery-slide img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
  transition: scale 620ms var(--simko-ease);
}

.product-gallery-slide:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: -4px;
}

/* The prompt that says the picture opens. Only where there is a pointer to
   reveal it: on touch the tap is the gesture and a permanent badge would sit on
   the product. */
.product-gallery-zoom {
  position: absolute;
  right: 0.75rem;
  bottom: 0.75rem;
  display: none;
  align-items: center;
  justify-content: center;
  width: var(--simko-touch);
  height: var(--simko-touch);
  color: var(--simko-ink);
  background-color: rgba(255, 255, 255, 0.92);
  border-radius: 50%;
  box-shadow: 0 6px 16px -8px rgba(26, 26, 26, 0.6);
  opacity: 0;
  transition: opacity var(--simko-speed) var(--simko-ease);
}

@media (hover: hover) and (pointer: fine) {
  .product-gallery-zoom {
    display: flex;
  }

  .product-gallery-slide:hover .product-gallery-zoom,
  .product-gallery-slide:focus-visible .product-gallery-zoom {
    opacity: 1;
  }

  .product-gallery-slide:hover img {
    scale: 1.04;
  }
}

/* Saving, in the top corner of the picture. Same disc, same muted heart and the
   same 44px target as the listing card's -- a shopper who saved things from the
   category grid on the way here should not have to learn a second control.
 *
 * Permanently visible, unlike the card's pair, which fade in on hover: there is
 * one of these on the page rather than one per card, so there is no clutter to
 * hide, and a control that only exists on hover is a control a phone never has.
 *
 * Above the dots and the arrows, which sit at z-index 2 -- it is in a corner
 * neither of them reaches, and this only settles the stacking. */
.product-gallery-save {
  position: absolute;
  top: 0.75rem;
  right: 0.75rem;
  z-index: 3;
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--simko-touch);
  height: var(--simko-touch);
  padding: 0;
  font-size: 1.125rem;
  color: var(--simko-ink-muted);
  background-color: rgba(255, 255, 255, 0.92);
  border: 0;
  border-radius: 50%;
  box-shadow: 0 4px 12px -6px rgba(26, 26, 26, 0.5);
  transition: color var(--simko-speed) var(--simko-ease), transform var(--simko-speed) var(--simko-ease);
}

.product-gallery-save:hover,
.product-gallery-save:focus-visible {
  color: var(--simko-brand);
  transform: scale(1.08);
}

.product-gallery-save:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

.product-gallery-save:active {
  transform: scale(0.94);
}

/* Dots over the foot of the picture, on a pill, as drawn. On the picture rather
   than under it because the panel below starts immediately -- a row of dots in
   that gap would push the name off the first screen. */
.product-gallery-dots {
  position: absolute;
  left: 50%;
  bottom: 0.85rem;
  transform: translateX(-50%);
  z-index: 2;
  display: flex;
  width: auto;
  align-items: center;
  gap: 0.35rem;
  padding: 0.4rem 0.55rem;
  border-radius: 999px;
  background-color: rgba(255, 255, 255, 0.82);
  box-shadow: 0 4px 14px -8px rgba(26, 26, 26, 0.7);
}

.product-gallery-dots:empty {
  display: none;
}

/* Swiper stretches its own pagination across the whole track --
   .swiper-pagination-bullets.swiper-pagination-horizontal sets left: 0,
   bottom: 8px and width: 100%, and two classes outrank the one above however
   late this file is loaded. Left as it was, the pill ran the full width of the
   picture and the centring transform then dragged it half a screen off the left
   edge. Three of our own classes to take it back -- written without Swiper's,
   which are not ours to depend on: it classes the element
   .swiper-pagination-bullets and .swiper-pagination-horizontal but not
   .swiper-pagination, and that is an implementation detail of the version in
   vendor/. */
.product-gallery .product-gallery-stage .product-gallery-dots {
  left: 50%;
  right: auto;
  bottom: 0.85rem;
  width: auto;
  transform: translateX(-50%);
}

/* Swiper inline-styles its bullets through these variables, so the size has to
   be set on them rather than on the element. */
.product-gallery-dots .swiper-pagination-bullet {
  width: 7px;
  height: 7px;
  margin: 0;
  background-color: #b9b0ad;
  opacity: 1;
  transition: width var(--simko-speed) var(--simko-ease), background-color var(--simko-speed) var(--simko-ease);
}

.product-gallery-dots .swiper-pagination-bullet-active {
  width: 22px;
  background-color: var(--simko-ink);
  border-radius: 4px;
}

/* Arrows sit on the picture's edges and only where a pointer can reveal them.
   [hidden] is never set on these -- they are printed only when there is more
   than one picture. */
.product-gallery-nav {
  position: absolute;
  top: 50%;
  z-index: 2;
  display: none;
  align-items: center;
  justify-content: center;
  width: var(--simko-touch);
  height: var(--simko-touch);
  margin-top: calc(var(--simko-touch) / -2);
  padding: 0;
  color: var(--simko-ink);
  background-color: rgba(255, 255, 255, 0.94);
  border: 1px solid var(--simko-border);
  border-radius: 50%;
  box-shadow: 0 8px 20px -12px rgba(26, 26, 26, 0.7);
  opacity: 0;
  transition: color var(--simko-speed) var(--simko-ease), opacity var(--simko-speed) var(--simko-ease);
}

.product-gallery-prev {
  left: 0.75rem;
}

.product-gallery-next {
  right: 0.75rem;
}

.product-gallery-nav:hover {
  color: var(--simko-brand);
}

.product-gallery-nav:focus-visible {
  opacity: 1;
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

.product-gallery-nav.swiper-button-disabled {
  opacity: 0;
  pointer-events: none;
}

@media (hover: hover) and (pointer: fine) {
  .product-gallery-nav {
    display: flex;
  }

  .product-gallery:hover .product-gallery-nav,
  .product-gallery:focus-within .product-gallery-nav {
    opacity: 1;
  }

  .product-gallery:hover .product-gallery-nav.swiper-button-disabled {
    opacity: 0.3;
  }
}

/* The strip under the picture. A row that scrolls sideways rather than a
   wrapping grid: extra pictures are a browse, and a second and third line of
   them would push the name and the price off the screen. */
.product-gallery-thumbs {
  display: flex;
  gap: 0.5rem;
  margin-top: 0.75rem;
  padding-bottom: 0.25rem;
  overflow-x: auto;
  scrollbar-width: none;
}

.product-gallery-thumbs::-webkit-scrollbar {
  display: none;
}

.product-gallery-thumb {
  flex: 0 0 auto;
  width: 64px;
  height: 64px;
  padding: 0;
  overflow: hidden;
  background-color: #f6ece8;
  border: 1px solid var(--simko-border);
  border-radius: 10px;
  transition: border-color var(--simko-speed) var(--simko-ease), transform var(--simko-speed) var(--simko-ease);
}

.product-gallery-thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.product-gallery-thumb:hover {
  border-color: var(--simko-brand);
  transform: translateY(-2px);
}

.product-gallery-thumb:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

/* Which picture is showing, marked by the brand outline. Two pixels so it reads
   at 64px, and inside the box so the row does not shift as the mark moves. */
.product-gallery-thumb.is-current {
  border-color: var(--simko-brand);
  box-shadow: inset 0 0 0 1px var(--simko-brand);
}

.product-gallery-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1;
  color: #cfc4c0;
  font-size: 2.5rem;
  background-color: #f6ece8;
  border-radius: 16px;
}

@media (min-width: 576px) {
  .product-gallery-stage {
    margin-inline: 0;
    border-radius: 16px;
    box-shadow: 0 16px 32px -22px rgba(26, 26, 26, 0.55);
  }

  .product-gallery-swiper {
    border-radius: 16px;
  }
}

/* ------------------------------------------------------------------
 * Lightbox (.simko-lightbox)
 *
 * Built by simko.js on the first tap, so a shopper who never opens it pays
 * nothing for it. There is no lightbox plugin in this install -- core's
 * product.twig calls magnificPopup, which is not shipped, so its 'click the
 * picture' has always been dead.
 * ------------------------------------------------------------------ */

.simko-lightbox {
  position: fixed;
  inset: 0;
  /* Above the cart drawer (1045) and Bootstrap's modal (1055): the lightbox is
     opened from the page and has to cover whatever is already on it. */
  z-index: 1080;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background-color: rgba(16, 16, 16, 0.94);
  opacity: 0;
  transition: opacity 220ms var(--simko-ease);
}

.simko-lightbox.is-open {
  opacity: 1;
}

.simko-lightbox-image {
  display: block;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: 8px;
  transform: scale(0.96);
  transition: transform 260ms var(--simko-ease), opacity 160ms var(--simko-ease);
}

.simko-lightbox.is-open .simko-lightbox-image {
  transform: none;
}

/* Set while the picture is being swapped, so one fades out and the next fades
   in rather than the frame flicking to the new file mid-size. */
.simko-lightbox-image.is-swapping {
  opacity: 0;
}

/* Dark discs with a pale edge, not the lifted white the rest of the storefront
   uses for a control on a picture. The picture here fills the frame, so these
   sit on top of whatever it happens to be -- and a party photograph is mostly
   pale pink, which a white glyph on a light wash disappears into completely. */
.simko-lightbox-close,
.simko-lightbox-nav {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--simko-touch);
  height: var(--simko-touch);
  padding: 0;
  color: #fff;
  font-size: 1.125rem;
  background-color: rgba(18, 18, 18, 0.62);
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 50%;
  transition: background-color var(--simko-speed) var(--simko-ease), border-color var(--simko-speed) var(--simko-ease);
}

.simko-lightbox-close:hover,
.simko-lightbox-nav:hover {
  background-color: rgba(18, 18, 18, 0.85);
  border-color: #fff;
}

.simko-lightbox-close:focus-visible,
.simko-lightbox-nav:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 2px;
}

.simko-lightbox-close {
  top: 1rem;
  right: 1rem;
}

.simko-lightbox-prev {
  left: 1rem;
  top: 50%;
  margin-top: calc(var(--simko-touch) / -2);
}

.simko-lightbox-next {
  right: 1rem;
  top: 50%;
  margin-top: calc(var(--simko-touch) / -2);
}

.simko-lightbox-count {
  position: absolute;
  left: 50%;
  bottom: 1rem;
  transform: translateX(-50%);
  margin: 0;
  color: rgba(255, 255, 255, 0.75);
  font-size: 0.8125rem;
  letter-spacing: 0.06em;
}

/* ------------------------------------------------------------------
 * Panel: name, identifier, rating, price (.product-panel)
 * ------------------------------------------------------------------ */

.product-panel {
  min-width: 0;
}

/* The buy form is a two-column grid so the stepper can sit in two different
   places without being printed twice: beside the name on a phone, exactly as
   drawn, and in the buy row from lg, where a panel 600px wide would otherwise
   leave it stranded in a corner a screen away from the button it counts for.
 *
 * A grid rather than flex because the two are not siblings in one row -- the
 * options sit between them in the source, and only grid can place an item into
 * a row that comes after markup it precedes.
 *
 * Everything else in the form spans both columns, so options, the buy row and
 * the messages under it run the full width whatever the stepper is doing. */
.product-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  column-gap: 1rem;
}

.product-form > * {
  grid-column: 1 / -1;
}

.product-headline {
  grid-column: 1;
  grid-row: 1;
  min-width: 0;
}

.product-qty {
  grid-column: 2;
  grid-row: 1;
}

.product-title {
  margin: 0;
  font-size: 1.625rem;
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.015em;
  color: var(--simko-ink);
}

.product-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.15rem 0.85rem;
  margin: 0.4rem 0 0;
  color: var(--simko-ink-muted);
  font-size: 0.8125rem;
  letter-spacing: 0.01em;
}

.product-meta a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.product-meta a:hover {
  color: var(--simko-brand);
}

.product-rating {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0.5rem 0 0;
}

.product-rating-stars {
  display: inline-flex;
  gap: 0.1rem;
  font-size: 0.8125rem;
  color: #f0a500;
}

.product-rating-stars .fa-regular {
  color: var(--simko-border);
}

.product-rating-link {
  color: var(--simko-ink-muted);
  font-size: 0.8125rem;
  text-decoration: none;
  border-bottom: 1px solid var(--simko-border);
  transition: color var(--simko-speed) var(--simko-ease), border-color var(--simko-speed) var(--simko-ease);
}

.product-rating-link:hover,
.product-rating-link:focus-visible {
  color: var(--simko-brand);
  border-color: var(--simko-brand);
  text-decoration: none;
}

/* Price. The currency's symbol is set at body size beside a much larger amount,
   which is why event/theme.php splits the formatted string in two -- baseline
   alignment does the rest, so the symbol sits on the line of the digits rather
   than floating above them. */
.product-price {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0 0.6rem;
  margin-top: 0.85rem;
}

.product-price-now {
  color: var(--simko-brand);
  font-size: 1.75rem;
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.01em;
}

.product-price-symbol {
  margin-right: 0.2rem;
  font-size: 1.0625rem;
  font-weight: 600;
}

/* Grey and struck, and only ever printed when there is a special to compare it
   with -- the red above is the price being paid. */
.product-price-was {
  color: var(--simko-ink-muted);
  font-size: 1.0625rem;
  font-weight: 400;
}

.product-price-tax {
  flex: 0 0 100%;
  margin-top: 0.15rem;
  color: var(--simko-ink-muted);
  font-size: 0.8125rem;
}

/* ------------------------------------------------------------------
 * Quantity stepper (.product-qty)
 * ------------------------------------------------------------------ */

.product-qty-control {
  display: flex;
  align-items: center;
  height: 52px;
  border: 1.5px solid var(--simko-ink);
  border-radius: 999px;
  transition: border-color var(--simko-speed) var(--simko-ease), box-shadow var(--simko-speed) var(--simko-ease);
}

.product-qty-control:focus-within {
  border-color: var(--simko-brand);
  box-shadow: 0 0 0 3px var(--simko-tint);
}

.product-qty-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 100%;
  padding: 0;
  color: var(--simko-ink);
  font-size: 0.875rem;
  background: none;
  border: 0;
  border-radius: 999px;
  transition: color var(--simko-speed) var(--simko-ease), transform var(--simko-speed) var(--simko-ease);
}

.product-qty-btn:hover {
  color: var(--simko-brand);
}

.product-qty-btn:active {
  transform: scale(0.88);
}

.product-qty-btn:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: -3px;
}

/* At the minimum there is nothing below to step to. Dimmed rather than removed,
   so the pill keeps its width and the number does not move. */
.product-qty-btn:disabled {
  color: #b9b9b9;
  pointer-events: none;
}

.product-qty-input {
  width: 3rem;
  height: 100%;
  padding: 0;
  color: var(--simko-ink);
  font-size: 1.125rem;
  font-weight: 700;
  text-align: center;
  background: none;
  border: 0;
  border-radius: 0;
  /* The pill is the field's outline; a second ring inside it reads as a box in
     a box. focus-within on the pill is what shows the field has focus. */
  box-shadow: none;
  outline: 0;
  -moz-appearance: textfield;
}

.product-qty-input::-webkit-outer-spin-button,
.product-qty-input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* Set for one beat by simko.js after a step, so the number reads as having been
   changed rather than silently replaced. */
.product-qty-input.is-bumped {
  animation: simko-qty-bump 220ms var(--simko-ease);
}

@keyframes simko-qty-bump {
  50% {
    transform: scale(1.18);
  }
}

/* Core's error handler puts .is-invalid on the field itself, which Bootstrap
   draws as a red border and a warning glyph inside the input -- both wrong
   inside a pill. The pill carries the state instead. */
.product-qty-input.is-invalid {
  background: none;
  border: 0;
  box-shadow: none;
  background-image: none;
  padding-right: 0;
}

.product-qty-control:has(.product-qty-input.is-invalid) {
  border-color: var(--simko-brand);
}

/* ------------------------------------------------------------------
 * Options and subscriptions
 * ------------------------------------------------------------------ */

.product-options {
  margin-top: 1.75rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--simko-border);
}

.product-block-title {
  margin: 0 0 1rem;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--simko-ink-muted);
}

.product-option + .product-option {
  margin-top: 1.15rem;
}

.product-option-label {
  display: block;
  margin-bottom: 0.4rem;
  color: var(--simko-ink);
  font-size: 0.9375rem;
  font-weight: 600;
}

/* Core marks a required option by putting .required on the wrapper and styling
   the label's ::before, which its own stylesheet only does for .form-label. */
.product-option.required > .product-option-label::after {
  content: '*';
  margin-left: 0.25rem;
  color: var(--simko-brand);
}

.product-control {
  min-height: var(--simko-control-h);
  padding: 0.5rem 0.9rem;
  color: var(--simko-ink);
  font-size: 0.9375rem;
  border: 1px solid var(--simko-border);
  border-radius: var(--simko-radius);
  box-shadow: none;
}

.product-control:focus {
  border-color: var(--simko-brand);
  box-shadow: 0 0 0 3px var(--simko-tint);
}

.product-choices {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

/* Every value is its own chip, with the whole chip as the target rather than a
   12px radio and a label beside it. */
.product-choice {
  position: relative;
  margin: 0;
  padding: 0;
}

.product-choice .form-check-input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.product-choice .form-check-label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: var(--simko-touch);
  padding: 0.4rem 0.9rem;
  color: var(--simko-ink);
  font-size: 0.9375rem;
  background-color: #fff;
  border: 1px solid var(--simko-border);
  border-radius: 999px;
  transition: color var(--simko-speed) var(--simko-ease), border-color var(--simko-speed) var(--simko-ease), background-color var(--simko-speed) var(--simko-ease);
}

.product-choice .form-check-input:hover + .form-check-label {
  border-color: var(--simko-brand);
}

.product-choice .form-check-input:checked + .form-check-label {
  color: var(--simko-brand);
  border-color: var(--simko-brand);
  background-color: var(--simko-tint);
  font-weight: 600;
}

.product-choice .form-check-input:focus-visible + .form-check-label {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

.product-choice-image {
  width: 28px;
  height: 28px;
  object-fit: cover;
  border-radius: 6px;
}

.product-option-note {
  margin-top: 0.5rem;
  color: var(--simko-ink-muted);
  font-size: 0.875rem;
}

.product-upload {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: var(--simko-touch);
  padding: 0.5rem 1.1rem;
  color: var(--simko-ink);
  font-size: 0.9375rem;
  font-weight: 600;
  background-color: #fff;
  border: 1px solid var(--simko-border);
  border-radius: var(--simko-radius);
  transition: color var(--simko-speed) var(--simko-ease), border-color var(--simko-speed) var(--simko-ease);
}

.product-upload:hover {
  color: var(--simko-brand);
  border-color: var(--simko-brand);
}

/* ------------------------------------------------------------------
 * Buy row (.product-buy)
 * ------------------------------------------------------------------ */

.product-buy {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-top: 1.5rem;
}

/* The one thing on the page that takes money, and the only filled control on
   it. Black rather than the brand red because the price beside it is already
   red -- two reds and neither is the loudest.
 *
 * Capped rather than edge to edge: a pill the full width of a tablet reads as a
 * band across the page. On a phone the cap is above the width available, so
 * there it is the full row. */
.product-cart {
  flex: 1 1 auto;
  max-width: 26rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 56px;
  padding: 0.5rem 1.5rem;
  color: #fff;
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background-color: var(--simko-ink);
  border: 0;
  border-radius: 999px;
  box-shadow: 0 14px 26px -16px rgba(26, 26, 26, 0.85);
  transition: background-color var(--simko-speed) var(--simko-ease), transform var(--simko-speed) var(--simko-ease), box-shadow var(--simko-speed) var(--simko-ease);
}

.product-cart:hover {
  background-color: #000;
  transform: translateY(-2px);
  box-shadow: 0 20px 32px -18px rgba(26, 26, 26, 0.9);
}

.product-cart:active {
  transform: translateY(0) scale(0.99);
}

.product-cart:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 3px;
}

/* Held for a beat after cart.add answers, so the button itself reports the
   result -- core's only confirmation was an alert prepended to the top of the
   page, which on a phone is a screen and a half above the button just pressed.
   The cart drawer opening is the other half of the answer. */
.product-cart.is-added {
  background-color: #1f7a43;
  pointer-events: none;
}

.product-cart[disabled] {
  opacity: 0.7;
}

/* #form-save exists only to carry the product id for the submits that reach it
   from elsewhere on the page: the heart on the picture, and comparing (with
   saving beside it when the product has no picture at all). */
.product-save-form {
  display: none;
}

/* Where cart.add's per-field answer lands. Hidden until it has something to
   say: core's handler adds .d-block, which is Bootstrap's own class for exactly
   this and is the only hook available. */
.product-error {
  display: none;
  margin-top: 0.6rem;
  color: var(--simko-brand);
  font-size: 0.875rem;
}

.product-error.d-block {
  display: block !important;
}

/* The warning cart.add answers with when the whole add failed rather than one
   field -- out of stock, or a required option missed. Written by simko.js. */
.product-alert:empty {
  display: none;
}

.product-alert {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  margin-top: 0.75rem;
  padding: 0.7rem 0.9rem;
  color: var(--simko-brand-dark);
  font-size: 0.875rem;
  line-height: 1.5;
  background-color: var(--simko-tint);
  border-radius: var(--simko-radius);
}

.product-note {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0.75rem 0 0;
  color: var(--simko-ink-muted);
  font-size: 0.875rem;
}

/* ------------------------------------------------------------------
 * Facts and extras
 * ------------------------------------------------------------------ */

.product-facts {
  margin: 1.5rem 0 0;
  padding: 0;
  list-style: none;
  font-size: 0.875rem;
}

.product-facts:empty {
  display: none;
}

.product-facts li {
  display: flex;
  gap: 0.4rem;
  padding: 0.2rem 0;
}

.product-fact-key {
  color: var(--simko-ink-muted);
}

.product-fact-value {
  color: var(--simko-ink);
  font-weight: 600;
}

/* ------------------------------------------------------------------
 * Sticky buy bar (.product-buybar)
 *
 * Phone and tablet only. From lg the panel sits beside a sticky gallery and the
 * real buy row stays reachable on its own, so a second copy of it pinned over
 * the page would only cover the content.
 * ------------------------------------------------------------------ */

.product-buybar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1030;
  padding: 0.65rem 0.75rem calc(0.65rem + env(safe-area-inset-bottom));
  background-color: rgba(255, 255, 255, 0.97);
  border-top: 1px solid var(--simko-border);
  box-shadow: 0 -10px 26px -18px rgba(26, 26, 26, 0.5);
  /* Off the bottom of the screen and out of the tab order until the real buy row
     has scrolled away -- simko.js sets .is-visible. visibility, not display, so
     the bar has something to slide from. */
  transform: translateY(105%);
  visibility: hidden;
  transition: transform 260ms var(--simko-ease), visibility 260ms var(--simko-ease);
}

.product-buybar.is-visible {
  transform: none;
  visibility: visible;
}

.product-buybar-inner {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.product-buybar-thumb {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  object-fit: cover;
  border-radius: 8px;
  background-color: #f6ece8;
}

.product-buybar-text {
  flex: 1 1 auto;
  min-width: 0;
}

.product-buybar-name {
  display: block;
  overflow: hidden;
  color: var(--simko-ink);
  font-size: 0.8125rem;
  line-height: 1.3;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.product-buybar-price {
  display: block;
  color: var(--simko-brand);
  font-size: 1rem;
  font-weight: 800;
  line-height: 1.3;
}

.product-buybar-cart {
  flex: 0 0 auto;
  min-height: var(--simko-touch);
  padding: 0 1.25rem;
  color: #fff;
  font-size: 0.875rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  background-color: var(--simko-ink);
  border: 0;
  border-radius: 999px;
  transition: background-color var(--simko-speed) var(--simko-ease);
}

.product-buybar-cart:hover {
  background-color: #000;
}

.product-buybar-cart:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

@media (min-width: 992px) {
  .product-buybar {
    display: none;
  }
}

/* ------------------------------------------------------------------
 * Description, specification, reviews (.product-details)
 * ------------------------------------------------------------------ */

.product-details {
  margin-top: 2.5rem;
}

/* Core's .nav-tabs draws a box round the active tab and a rule under the row.
   An underline marks the open one instead -- the same mark the main menu uses,
   so a tab and a menu item are read the same way. The row scrolls sideways
   rather than wrapping: three tabs and a review count will not fit on a small
   phone, and a second line of tabs reads as two rows of chrome. */
.product-tabs {
  display: flex;
  flex-wrap: nowrap;
  gap: 0.25rem;
  margin: 0;
  padding: 0;
  overflow-x: auto;
  border-bottom: 1px solid var(--simko-border);
  scrollbar-width: none;
}

.product-tabs::-webkit-scrollbar {
  display: none;
}

.product-tab.nav-link {
  position: relative;
  padding: 0.85rem 1rem;
  color: var(--simko-ink-muted);
  font-size: 0.9375rem;
  font-weight: 600;
  white-space: nowrap;
  background: none;
  border: 0;
  border-radius: 0;
  transition: color var(--simko-speed) var(--simko-ease);
}

.product-tab.nav-link::after {
  content: '';
  position: absolute;
  left: 1rem;
  right: 1rem;
  bottom: -1px;
  height: 2px;
  background-color: var(--simko-brand);
  transform: scaleX(0);
  transition: transform var(--simko-speed) var(--simko-ease);
}

.product-tab.nav-link:hover {
  color: var(--simko-ink);
  border: 0;
}

.product-tab.nav-link.active {
  color: var(--simko-ink);
  background: none;
  border: 0;
}

.product-tab.nav-link.active::after,
.product-tab.nav-link:hover::after {
  transform: scaleX(1);
}

.product-tab.nav-link:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: -2px;
}

.product-tab-content {
  padding-top: 1.5rem;
}

/* The store owner's own HTML, so this styles what a rich-text field can produce
   rather than a fixed shape. 68ch because a description running the width of a
   desktop panel is a line the eye loses its place in. */
.product-copy {
  max-width: 68ch;
  color: #3a3a3a;
  font-size: 0.9375rem;
  line-height: 1.7;
}

.product-copy > *:first-child {
  margin-top: 0;
}

.product-copy > *:last-child {
  margin-bottom: 0;
}

.product-copy h1,
.product-copy h2,
.product-copy h3,
.product-copy h4 {
  margin: 1.75rem 0 0.75rem;
  color: var(--simko-ink);
  font-weight: 700;
  line-height: 1.25;
}

.product-copy h1,
.product-copy h2 {
  font-size: 1.25rem;
}

.product-copy h3,
.product-copy h4 {
  font-size: 1.0625rem;
}

.product-copy ul,
.product-copy ol {
  margin: 0.75rem 0;
  padding-left: 1.25rem;
}

.product-copy li {
  margin-bottom: 0.35rem;
}

.product-copy img {
  max-width: 100%;
  height: auto;
  border-radius: 12px;
}

.product-copy a {
  color: var(--simko-brand);
}

.product-copy table {
  width: 100%;
  margin: 1rem 0;
  border-collapse: collapse;
}

.product-copy th,
.product-copy td {
  padding: 0.5rem 0.75rem;
  border: 1px solid var(--simko-border);
  text-align: left;
}

.product-tags {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin: 1.75rem 0 0;
}

.product-tags-label {
  color: var(--simko-ink-muted);
  font-size: 0.8125rem;
  font-weight: 600;
}

.product-tag {
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  padding: 0.25rem 0.8rem;
  color: var(--simko-ink);
  font-size: 0.8125rem;
  text-decoration: none;
  background-color: #f7f7f7;
  border-radius: 999px;
  transition: color var(--simko-speed) var(--simko-ease), background-color var(--simko-speed) var(--simko-ease);
}

.product-tag:hover {
  color: var(--simko-brand);
  background-color: var(--simko-tint);
  text-decoration: none;
}

/* Specification. Core's bordered table put every attribute in a two-column grid
   that on a phone squeezed the value into about eight characters. Rows that
   stack under their label instead, and become two columns from sm. */
.product-spec + .product-spec {
  margin-top: 2rem;
}

.product-spec-title {
  margin: 0 0 0.75rem;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--simko-ink-muted);
}

.product-spec-list {
  margin: 0;
}

.product-spec-row {
  display: grid;
  gap: 0.1rem;
  padding: 0.7rem 0;
  border-bottom: 1px solid var(--simko-border);
}

.product-spec-row dt {
  color: var(--simko-ink-muted);
  font-size: 0.875rem;
  font-weight: 400;
}

.product-spec-row dd {
  margin: 0;
  color: var(--simko-ink);
  font-size: 0.9375rem;
  font-weight: 600;
}

@media (min-width: 576px) {
  .product-spec-row {
    grid-template-columns: minmax(0, 14rem) minmax(0, 1fr);
    gap: 1rem;
    align-items: baseline;
  }
}

/* ------------------------------------------------------------------
 * Reviews (.product-reviews-*, .product-review-*, .product-stars)
 *
 * Core's pane was a table per review with the stars printed under the text, and
 * a rating control of five bare radio circles between the words 'Bad' and
 * 'Good'. Here the score leads, each review is a card, and the radios are the
 * stars themselves.
 * ------------------------------------------------------------------ */

/* The average, at the size the price is set in: it is the one number a shopper
   scanning the tab came for. */
/* Capped to a reading measure: on a wide screen the head of a card would
   otherwise put the name at the far left and the stars 1200px away from it. */
.product-reviews-summary,
.product-reviews-list {
  max-width: 46rem;
}

.product-reviews-summary {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 1.1rem 1.25rem;
  background-color: #faf5f3;
  border-radius: 12px;
}

.product-reviews-score {
  display: flex;
  align-items: baseline;
  margin: 0;
  font-weight: 800;
  line-height: 1;
}

.product-reviews-score-value {
  font-size: 2.25rem;
}

.product-reviews-score-max {
  color: var(--simko-ink-muted);
  font-size: 1rem;
  font-weight: 600;
}

.product-reviews-stars {
  font-size: 0.9375rem;
}

.product-reviews-count {
  margin: 0.3rem 0 0;
  color: var(--simko-ink-muted);
  font-size: 0.8125rem;
}

.product-reviews-list {
  margin-top: 1.5rem;
}

.product-review-items {
  display: grid;
  gap: 0.75rem;
}

.product-review {
  padding: 1.1rem 1.25rem;
  border: 1px solid var(--simko-border);
  border-radius: 12px;
  transition: border-color var(--simko-speed) var(--simko-ease), box-shadow var(--simko-speed) var(--simko-ease);
}

.product-review:hover {
  border-color: #d2d2d2;
  box-shadow: 0 10px 24px -20px rgba(26, 26, 26, 0.55);
}

.product-review-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.75rem;
}

/* Reviewers have no picture in OpenCart, so the initial stands in. Five
   identical silhouettes down the list would be five pieces of nothing. */
.product-review-avatar {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  color: #fff;
  font-size: 0.9375rem;
  font-weight: 700;
  background-color: var(--simko-brand);
  border-radius: 50%;
}

.product-review-who {
  min-width: 0;
  margin-right: auto;
}

.product-review-author {
  margin: 0;
  font-size: 0.9375rem;
  font-weight: 700;
}

.product-review-date {
  margin: 0;
  color: var(--simko-ink-muted);
  font-size: 0.75rem;
}

.product-review-stars {
  display: inline-flex;
  gap: 0.1rem;
  font-size: 0.8125rem;
  color: #f0a500;
}

.product-review-stars .fa-regular {
  color: var(--simko-border);
}

.product-review-text {
  margin-top: 0.8rem;
  font-size: 0.9375rem;
  line-height: 1.65;
}

.product-review-empty {
  display: grid;
  justify-items: center;
  gap: 0.6rem;
  padding: 2.5rem 1.25rem;
  color: var(--simko-ink-muted);
  text-align: center;
  background-color: #faf5f3;
  border-radius: 12px;
}

.product-review-empty i {
  font-size: 1.5rem;
  color: var(--simko-brand);
}

.product-review-empty p {
  margin: 0;
  font-size: 0.9375rem;
}

.product-review-pagination:empty {
  display: none;
}

/* The form. Rating first, because it is the field every reviewer fills and it
   makes the form read shorter than a name box on top of a textarea does. */
.product-review-form {
  max-width: 40rem;
  margin-top: 2rem;
  padding-top: 1.75rem;
  border-top: 1px solid var(--simko-border);
}

.product-review-form-title {
  margin: 0;
  font-size: 1.0625rem;
  font-weight: 800;
}

.product-review-field {
  margin-top: 1.25rem;
}

.product-review-label {
  display: block;
  margin-bottom: 0.45rem;
  color: var(--simko-ink-muted);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.product-review-field.required .product-review-label::after {
  content: '*';
  margin-left: 0.25rem;
  color: var(--simko-brand);
}

.product-review-form .product-control {
  display: block;
  width: 100%;
}

.product-review-note {
  margin: 0.5rem 0 0;
  color: var(--simko-ink-muted);
  font-size: 0.75rem;
}

.product-review-note .text-danger {
  color: var(--simko-brand);
}

.product-review-captcha {
  margin-top: 1.25rem;
}

.product-review-actions {
  margin-top: 1.5rem;
}

/* The same black pill the buy button is, one step smaller: this submit posts an
   opinion, not money, and two identical pills on one page compete. */
.product-review-submit {
  min-height: var(--simko-touch);
  padding: 0.6rem 1.75rem;
  color: #fff;
  font-size: 0.875rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background-color: var(--simko-ink);
  border: 0;
  border-radius: 999px;
  transition: background-color var(--simko-speed) var(--simko-ease), transform var(--simko-speed) var(--simko-ease);
}

.product-review-submit:hover,
.product-review-submit:focus-visible {
  background-color: var(--simko-brand);
  transform: translateY(-1px);
}

.product-review-submit[disabled] {
  opacity: 0.6;
  transform: none;
}

.product-review-login {
  margin: 1.5rem 0 0;
  padding: 1rem 1.25rem;
  font-size: 0.9375rem;
  background-color: #faf5f3;
  border-radius: 12px;
}

.product-review-login a {
  color: var(--simko-brand);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* The rating control. The radios are printed 5..1 and the row is reversed, so
   'fill this star and every one before it' is the sibling combinator and needs
   no script: the control works on a page whose JS never arrives. */
.product-review-rating {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.75rem;
}

.product-stars {
  position: relative;
  display: flex;
  flex-direction: row-reverse;
  justify-content: flex-end;
  margin-left: -0.35rem;
}

/* Kept in the layout and focusable -- only invisible. display: none would take
   it out of the tab order and out of the form. */
.product-stars-input {
  position: absolute;
  top: 0;
  left: 0;
  width: 1px;
  height: 1px;
  margin: 0;
  opacity: 0;
  pointer-events: none;
}

.product-stars-label {
  display: grid;
  place-items: center;
  min-width: var(--simko-touch);
  min-height: var(--simko-touch);
  color: var(--simko-border);
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
  transition: color var(--simko-speed) var(--simko-ease);
}

.product-stars-label i {
  transition: transform var(--simko-speed) var(--simko-ease);
}

.product-stars-input:checked ~ .product-stars-label {
  color: #f0a500;
}

/* Pointing at a star previews that score, so the fill has to follow the cursor
   rather than the stored value while the row is under it. */
@media (hover: hover) {
  .product-stars:hover .product-stars-label {
    color: var(--simko-border);
  }

  .product-stars:hover .product-stars-label:hover,
  .product-stars:hover .product-stars-label:hover ~ .product-stars-label {
    color: #f0a500;
  }

  .product-stars-label:hover i {
    transform: scale(1.12);
  }
}

.product-stars-input:focus-visible + .product-stars-label {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
  border-radius: 6px;
}

.product-stars.is-invalid .product-stars-label {
  color: rgba(218, 34, 41, 0.35);
}

/* Confirms the tap landed, on the stars rather than beside them. */
.product-stars.is-picked .product-stars-input:checked ~ .product-stars-label i {
  animation: simko-star-pop 420ms var(--simko-ease);
}

@keyframes simko-star-pop {
  0% {
    transform: scale(1);
  }

  35% {
    transform: scale(1.28);
  }

  100% {
    transform: scale(1);
  }
}

.product-stars-hint {
  color: var(--simko-ink-muted);
  font-size: 0.8125rem;
}

/* What the write answered with. Green for the thanks, brand tint for a refusal
   -- .product-alert's own colours. */
.product-alert.is-success {
  color: #1f7a43;
  background-color: rgba(31, 122, 67, 0.09);
}

/* Fields a captcha extension prints inside the pane, which the child theme
   cannot put its own class on. */
#tab-review .form-control:focus,
#tab-review .form-select:focus {
  border-color: var(--simko-brand);
  box-shadow: 0 0 0 3px var(--simko-tint);
}

/* ------------------------------------------------------------------
 * Related products (.product-related)
 * ------------------------------------------------------------------ */

.product-related {
  margin-top: 3.5rem;
  padding-top: 2.5rem;
  border-top: 1px solid var(--simko-border);
}

.product-related-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1rem;
}

@media (min-width: 992px) {
  .product-related-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 1.5rem;
  }
}

/* ------------------------------------------------------------------
 * Two columns from lg
 *
 * The gallery follows the page down while the panel is read, and keeps
 * following while the description below it is read -- the picture is what the
 * copy is describing.
 * ------------------------------------------------------------------ */

@media (min-width: 992px) {
  .product-main {
    flex-direction: row;
    align-items: flex-start;
    gap: 3rem;
    margin-bottom: 3.5rem;
  }

  .product-gallery {
    flex: 1 1 0;
    position: sticky;
    top: 1.5rem;
  }

  .product-panel {
    flex: 1 1 0;
    padding-top: 0.5rem;
  }

  /* The stepper drops out of the headline row and into the buy row. The columns
     swap proportions with it: the stepper is a fixed width and the button beside
     it takes the rest, where on a phone it was the name that took the rest.
   *
     Both are auto-placed into the same row -- the grid's own placement keeps a
     definite-column item on the cursor's row when the cell is free, and the
     stepper is printed immediately before the buy row. */
  .product-form {
    grid-template-columns: auto minmax(0, 1fr);
  }

  .product-headline {
    grid-column: 1 / -1;
  }

  .product-qty {
    grid-column: 1;
    grid-row: auto;
    margin-top: 1.5rem;
    align-self: center;
  }

  .product-buy {
    grid-column: 2;
    align-self: center;
  }

  .product-title {
    font-size: 2rem;
  }

  .product-price-now {
    font-size: 2rem;
  }

  .product-gallery-thumb {
    width: 72px;
    height: 72px;
  }
}

@media (min-width: 1200px) {
  .product-main {
    gap: 4rem;
  }
}

/* ------------------------------------------------------------------
 * Product page: arrival
 *
 * Same machinery as the rest of the storefront -- .simko-js at parse time,
 * .simko-reveal-in as each block is scrolled to, so nothing is hidden unless
 * something is guaranteed to un-hide it. The gallery and the panel arrive
 * together with the panel a beat behind, which is the order they are read in.
 * ------------------------------------------------------------------ */

/* The gallery and the panel are the top of the page, so they arrive on load
   rather than on a scroll -- see arrive() in simko.js for why the observer
   cannot be trusted with a block that is tall and already on screen. The
   details block further down is a scroll reveal like every other section. */
.simko-js .product-gallery.simko-arrive,
.simko-js .product-panel.simko-arrive,
.simko-js .product-details.simko-reveal {
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity 520ms var(--simko-ease),
    transform 520ms var(--simko-ease);
}

.simko-js .product-panel.simko-arrive {
  transition-delay: 90ms;
}

.simko-js .product-gallery.simko-arrive-in,
.simko-js .product-panel.simko-arrive-in,
.simko-js .product-details.simko-reveal-in {
  opacity: 1;
  transform: none;
}

/* The related row arrives card by card, on the same 140ms start and 80ms step
   as the homepage rows. */
.simko-js .product-related.simko-reveal .product-related-item {
  opacity: 0;
  transform: translateY(28px) scale(0.97);
  transition:
    opacity 520ms var(--simko-ease),
    transform 520ms var(--simko-ease);
  transition-delay: calc(140ms + (var(--card-index, 0) * 80ms));
}

.simko-js .product-related.simko-reveal-in .product-related-item {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .product-gallery-slide img,
  .product-gallery-zoom,
  .product-gallery-nav,
  .product-gallery-thumb,
  .product-qty-control,
  .product-qty-btn,
  .product-cart,
  .product-gallery-save,
  .product-tab.nav-link,
  .product-tab.nav-link::after,
  .product-tag,
  .simko-lightbox,
  .simko-lightbox-image,
  .simko-lightbox-close,
  .simko-lightbox-nav {
    transition: none;
  }

  /* What these states mean is the colour, which stays. What goes is what
     moves. */
  .product-gallery-slide:hover img {
    scale: 1;
  }

  .product-gallery-thumb:hover,
  .product-qty-btn:active,
  .product-cart:hover,
  .product-cart:active,
  .product-gallery-save:hover,
  .product-gallery-save:focus-visible,
  .product-gallery-save:active {
    transform: none;
  }

  .product-qty-input.is-bumped {
    animation: none;
  }

  /* The bar still arrives and leaves; it simply does not slide. */
  .product-buybar {
    transition: none;
  }
}

/* ------------------------------------------------------------------
 * Cart page (.cart-page)
 *
 * Core rendered one five-column table -- image, product, quantity, unit price,
 * total -- with the totals in its footer. At 390px that table is wider than the
 * screen: the two money columns sit off the right edge, and the quantity cell
 * holds a text field beside two filled red buttons that wrap on top of each
 * other. On a desktop it reads as a spreadsheet of a shopping bag.
 *
 * Here each line is its own card laid out on a grid, so one set of markup is a
 * stacked card on a phone and a row from md up, and the totals move into a panel
 * that sits beside the items from lg and sticks while a long cart is scrolled.
 *
 * Nothing new is invented for it: the item cards are the listing card's border,
 * radius and white ground; the checkout button is the drawer's checkout button;
 * the stepper is the product page's stepper at a smaller size, down to sharing
 * its bump animation. Red is spent on the one action the page is for.
 * ------------------------------------------------------------------ */

.cart-page {
  padding-bottom: 3rem;
}

.cart-head {
  margin-bottom: 1.25rem;
}

.cart-title {
  margin: 0;
  font-size: 1.625rem;
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.015em;
  color: var(--simko-ink);
}

/* Core printed the weight inside the H1, in brackets, so the page was called
   'Shopping Cart (25.00kg)'. It is a shipping detail; it belongs on the quiet
   line with the count. */
.cart-head-meta {
  margin: 0.35rem 0 0;
  font-size: 0.875rem;
  color: var(--simko-ink-muted);
}

.cart-layout {
  display: grid;
  gap: 1.25rem;
}

/* ------------------------------------------------------------------
 * One line of the cart (.cart-item)
 * ------------------------------------------------------------------ */

.cart-items {
  display: grid;
  gap: 0.75rem;
  margin: 0;
}

/* The named areas are the whole responsive story for a row: only the column
   tracks and the area map change from md up, never the markup. */
.cart-item {
  position: relative;
  display: grid;
  grid-template-columns: 76px minmax(0, 1fr) 2rem;
  grid-template-areas:
    'thumb body   remove'
    'foot  foot   foot'
    'note  note   note';
  align-items: start;
  gap: 0.875rem;
  padding: 0.875rem;
  border: 1px solid var(--simko-border);
  border-radius: 14px;
  background-color: #fff;
  overflow: hidden;
  transition: border-color var(--simko-speed) var(--simko-ease);
}

.cart-item-thumb {
  grid-area: thumb;
  display: block;
  width: 76px;
  border-radius: 10px;
  overflow: hidden;
  /* The catalogue's thumbnails are square already; the ground shows through
     while one loads rather than the row collapsing to nothing. */
  background-color: var(--simko-tint);
}

.cart-item-thumb img {
  display: block;
  width: 100%;
  aspect-ratio: 1;
  object-fit: cover;
}

.cart-item-thumb-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  aspect-ratio: 1;
  color: var(--simko-brand);
  font-size: 1.5rem;
}

.cart-item-body {
  grid-area: body;
  min-width: 0;
}

/* Two lines, then clipped -- the same limit the listing card puts on a name.
   Product names in this catalogue run long, and a third line pushes the amount
   and the total out of line with the row above. */
.cart-item-name {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-size: 0.9375rem;
  font-weight: 700;
  line-height: 1.3;
  color: var(--simko-ink);
  text-decoration: none;
  transition: color var(--simko-speed) var(--simko-ease);
}

.cart-item-name:hover,
.cart-item-name:focus-visible {
  color: var(--simko-brand);
  text-decoration: none;
}

.cart-item-meta {
  margin: 0.3rem 0 0;
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--simko-ink-muted);
}

.cart-item-unit {
  margin: 0.4rem 0 0;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--simko-ink);
}

.cart-item-unit span {
  font-weight: 400;
  color: var(--simko-ink-muted);
}

/* Core marked a short-stocked line with three asterisks and left the reader to
   find the sentence explaining them above the table. */
.cart-item-flag {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  margin: 0.45rem 0 0;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--simko-brand);
}

.cart-item-foot {
  grid-area: foot;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.cart-item-qty {
  margin: 0;
}

.cart-item-total {
  margin: 0;
  font-size: 1.0625rem;
  font-weight: 800;
  color: var(--simko-ink);
  white-space: nowrap;
  transition: opacity var(--simko-speed) var(--simko-ease);
}

/* Destructive, and one tap from checkout, so it stays quiet until it is aimed
   at -- the same treatment the cart drawer gives its own remove control. */
.cart-item-remove {
  grid-area: remove;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  margin: -0.25rem -0.25rem 0 0;
  border-radius: 50%;
  color: var(--simko-ink-muted);
  font-size: 0.875rem;
  text-decoration: none;
  transition: color var(--simko-speed) var(--simko-ease), background-color var(--simko-speed) var(--simko-ease);
}

.cart-item-remove:hover,
.cart-item-remove:focus-visible {
  color: var(--simko-brand);
  background-color: var(--simko-tint);
}

.cart-item-remove:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

.cart-item-note {
  grid-area: note;
  margin: 0;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--simko-brand);
}

.cart-item-note:empty {
  display: none;
}

/* In flight. The amounts on the row are about to be replaced by the server's
   version of them, so they step back rather than sitting there looking settled,
   and a line sweeps the top edge for as long as the request is out. */
.cart-item.is-busy {
  cursor: progress;
}

.cart-item.is-busy .cart-item-total {
  opacity: 0.4;
}

.cart-item.is-busy::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 40%;
  height: 2px;
  border-radius: 0 2px 2px 0;
  background-color: var(--simko-brand);
  animation: simko-cart-working 1s var(--simko-ease) infinite;
}

@keyframes simko-cart-working {
  0% {
    transform: translateX(-100%);
  }

  100% {
    transform: translateX(250%);
  }
}

/* The request never landed, so the number in the field is not the number the
   cart holds. Said on the row as well as in the note under it. */
.cart-item.is-stale {
  border-color: var(--simko-brand-light);
}

.cart-item.is-unavailable .cart-item-thumb {
  opacity: 0.55;
}

/* ------------------------------------------------------------------
 * Quantity stepper (.cart-qty)
 *
 * The product page's stepper, one size down. Same pill, same bump, so changing
 * an amount feels the same in both places -- and the update button is gone from
 * beside it, because cartPage() posts the amount once the taps stop.
 * ------------------------------------------------------------------ */

.cart-qty {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--simko-border);
  border-radius: 999px;
  background-color: #fff;
  transition: border-color var(--simko-speed) var(--simko-ease);
}

.cart-qty:focus-within {
  border-color: var(--simko-brand);
}

.cart-qty-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--simko-ink);
  font-size: 0.75rem;
  transition: color var(--simko-speed) var(--simko-ease), background-color var(--simko-speed) var(--simko-ease);
}

.cart-qty-btn:hover:not(:disabled) {
  color: var(--simko-brand);
  background-color: var(--simko-tint);
}

.cart-qty-btn:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: -2px;
}

/* At one there is nothing below to step to: emptying a line is the remove
   control's job, not something a held finger should reach. */
.cart-qty-btn:disabled {
  color: #c9c9c9;
  background: none;
}

.cart-qty-input {
  width: 2.25rem;
  padding: 0;
  border: 0;
  background: none;
  font-size: 0.9375rem;
  font-weight: 700;
  color: var(--simko-ink);
  text-align: center;
  -moz-appearance: textfield;
}

.cart-qty-input:focus {
  outline: none;
}

.cart-qty-input::-webkit-outer-spin-button,
.cart-qty-input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* Set for one beat by simko.js after a step, so the number reads as having been
   changed rather than silently replaced. Shares the product page's keyframes. */
.cart-qty-input.is-bumped {
  animation: simko-qty-bump 220ms var(--simko-ease);
}

/* Core's error handler puts .is-invalid on the field, which Bootstrap draws as a
   red border and a glyph inside the input -- both wrong inside a pill. The pill
   carries the state instead. */
.cart-qty-input.is-invalid {
  background: none;
  border: 0;
  box-shadow: none;
  background-image: none;
  padding-right: 0;
}

.cart-qty:has(.cart-qty-input.is-invalid) {
  border-color: var(--simko-brand);
}

/* ------------------------------------------------------------------
 * Summary panel (.cart-summary)
 *
 * Core's totals were three more rows of the products table, right-aligned under
 * a colspan, with the amount that will actually be charged set no differently
 * from the sub-total above it.
 * ------------------------------------------------------------------ */

.cart-aside {
  display: grid;
  gap: 1rem;
  align-content: start;
}

.cart-summary {
  padding: 1.125rem 1.25rem 1.25rem;
  border: 1px solid var(--simko-border);
  border-radius: 14px;
  /* The one surface on the page that is not the content ground, so the panel
     reads as the thing you act from rather than another item card. */
  background-color: #fafafa;
}

.cart-summary-title {
  margin: 0 0 0.875rem;
  font-size: 1rem;
  font-weight: 800;
  color: var(--simko-ink);
}

.cart-summary-rows {
  margin: 0 0 1rem;
  font-size: 0.875rem;
}

.cart-summary-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.25rem 0;
  color: var(--simko-ink-muted);
}

/* The last line is the amount that will be charged: the one number in the panel
   worth finding without reading. */
.cart-summary-row-final {
  margin-top: 0.5rem;
  padding-top: 0.65rem;
  border-top: 1px solid var(--simko-border);
  color: var(--simko-ink);
  font-size: 1.125rem;
  font-weight: 800;
}

.cart-summary-row-final span:last-child {
  color: var(--simko-brand);
}

.cart-checkout {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 3rem;
  padding: 0 1rem;
  color: #fff;
  background-color: var(--simko-brand);
  border-radius: var(--simko-radius);
  font-size: 0.9375rem;
  font-weight: 700;
  text-decoration: none;
  transition: background-color var(--simko-speed) var(--simko-ease);
}

.cart-checkout:hover,
.cart-checkout:focus-visible {
  color: #fff;
  background-color: var(--simko-brand-dark);
  text-decoration: none;
}

.cart-checkout:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

.cart-checkout i {
  font-size: 0.75rem;
}

/* Says in one line what the estimator panel used to work out on the page. */
.cart-summary-note {
  margin: 0.75rem 0 0;
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--simko-ink-muted);
  text-align: center;
}

/* ------------------------------------------------------------------
 * Coupon and reward panels (.cart-extras)
 * ------------------------------------------------------------------ */

.cart-extras-title {
  margin: 0 0 0.6rem;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--simko-ink-muted);
}

.cart-accordion {
  --bs-accordion-border-color: var(--simko-border);
  --bs-accordion-border-radius: 14px;
  --bs-accordion-inner-border-radius: 13px;
  --bs-accordion-bg: #fff;
  --bs-accordion-btn-focus-box-shadow: none;
}

.cart-accordion-item {
  border-color: var(--simko-border);
}

/* Bootstrap's accordion button is a 1rem link-blue row with a chevron drawn from
   a background SVG that it recolours to the theme's primary on open. Neither
   colour is this theme's, and the row was taller than the field it opens. */
.cart-accordion-btn.accordion-button {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  min-height: var(--simko-touch);
  padding: 0.7rem 1rem;
  font-size: 0.875rem;
  font-weight: 700;
  color: var(--simko-ink);
  background-color: #fff;
  box-shadow: none;
}

.cart-accordion-btn.accordion-button:not(.collapsed) {
  color: var(--simko-brand);
  background-color: var(--simko-tint);
}

.cart-accordion-btn.accordion-button > i {
  font-size: 0.8125rem;
  color: var(--simko-brand);
}

.cart-accordion-btn.accordion-button:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: -2px;
}

/* Bootstrap's chevron is a data-URI SVG stroked in --bs-body-color and swapped
   for a primary-coloured copy when the panel opens. Recolouring it means
   shipping two more copies of the same picture, so the caret is drawn from the
   border of a pseudo-element instead and simply turns. */
.cart-accordion-btn.accordion-button::after {
  width: 0.5rem;
  height: 0.5rem;
  margin-left: auto;
  border: 0;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  background: none;
  transform: rotate(45deg);
  transform-origin: 60% 60%;
  transition: transform var(--simko-speed) var(--simko-ease);
}

.cart-accordion-btn.accordion-button:not(.collapsed)::after {
  transform: rotate(225deg);
}

.cart-accordion-body.accordion-body {
  padding: 0.875rem 1rem 1rem;
}

.cart-code {
  transition: opacity var(--simko-speed) var(--simko-ease);
}

.cart-code.is-busy {
  opacity: 0.6;
  pointer-events: none;
}

/* Field and action as one control. Core stacked a col-md-4 label above a
   full-width field, then put Apply beside a filled red Remove underneath, which
   at panel width gave the destructive button equal billing. */
.cart-code-row {
  display: flex;
  align-items: stretch;
  border: 1px solid var(--simko-border);
  border-radius: var(--simko-radius);
  overflow: hidden;
  background-color: #fff;
  transition: border-color var(--simko-speed) var(--simko-ease);
}

.cart-code-row:focus-within {
  border-color: var(--simko-brand);
}

.cart-code-input {
  flex: 1;
  min-width: 0;
  height: var(--simko-touch);
  padding: 0 0.75rem;
  border: 0;
  background: none;
  font-size: 0.875rem;
  color: var(--simko-ink);
}

.cart-code-input:focus {
  outline: none;
}

.cart-code-input::placeholder {
  color: var(--simko-ink-muted);
}

.cart-code-apply {
  flex: none;
  height: var(--simko-touch);
  padding: 0 0.9rem;
  border: 0;
  background-color: var(--simko-brand);
  color: #fff;
  font-size: 0.8125rem;
  font-weight: 700;
  white-space: nowrap;
  transition: background-color var(--simko-speed) var(--simko-ease);
}

.cart-code-apply:hover {
  background-color: var(--simko-brand-dark);
}

.cart-code-apply:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: -2px;
}

/* Only rendered once there is a code to clear, and then as a plain word: taking
   a discount off is a correction, not one of the panel's two equal choices. */
.cart-code-clear {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  min-height: var(--simko-touch);
  margin-top: 0.15rem;
  padding: 0;
  border: 0;
  background: none;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--simko-ink-muted);
  transition: color var(--simko-speed) var(--simko-ease);
}

.cart-code-clear:hover,
.cart-code-clear:focus-visible {
  color: var(--simko-brand);
}

/* Where the answer lands. Core's went to #alert at the top of the document,
   which on a phone is a screen away from the field that was submitted. */
.cart-code-feedback {
  margin: 0.5rem 0 0;
  font-size: 0.75rem;
  line-height: 1.45;
  font-weight: 600;
}

.cart-code-feedback:empty {
  display: none;
}

.cart-code-feedback.is-error {
  color: var(--simko-brand);
}

.cart-code-feedback.is-success {
  color: #1f7a3d;
}

/* ------------------------------------------------------------------
 * Leaving the cart (.cart-back) and the empty cart (.cart-empty)
 * ------------------------------------------------------------------ */

/* Core gave this the same button shape as Checkout, on the same line, so the two
   exits from the page competed. Going back to the catalogue is a link. */
.cart-back {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: var(--simko-touch);
  margin-top: 0.25rem;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--simko-ink-muted);
  text-decoration: none;
  transition: color var(--simko-speed) var(--simko-ease);
}

.cart-back:hover,
.cart-back:focus-visible {
  color: var(--simko-brand);
  text-decoration: none;
}

.cart-back i {
  font-size: 0.75rem;
}

/* Core's empty cart was the H1, one sentence, and a right-aligned Continue
   button -- which on this storefront is the most likely first sight of the page.
   It gets the same treatment the empty listing gets, and says where to go. */
.cart-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  padding: 3.5rem 1.5rem 4rem;
  text-align: center;
  border: 1px solid var(--simko-border);
  border-radius: 20px;
  background-color: #fff;
}

.cart-empty-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 4.5rem;
  height: 4.5rem;
  border-radius: 50%;
  background-color: var(--simko-tint);
  color: var(--simko-brand);
  font-size: 1.75rem;
}

.cart-empty-title {
  margin: 0.25rem 0 0;
  font-size: 1.375rem;
  font-weight: 800;
  color: var(--simko-ink);
}

.cart-empty-text {
  max-width: 34ch;
  margin: 0;
  color: var(--simko-ink-muted);
}

.cart-empty-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: var(--simko-touch);
  margin-top: 0.5rem;
  padding: 0.5rem 1.5rem;
  border-radius: var(--simko-radius);
  background-color: var(--simko-brand);
  color: #fff;
  font-weight: 700;
  text-decoration: none;
  transition: background-color var(--simko-speed) var(--simko-ease);
}

.cart-empty-btn:hover,
.cart-empty-btn:focus-visible {
  background-color: var(--simko-brand-dark);
  color: #fff;
  text-decoration: none;
}

.cart-empty-btn:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

.cart-empty-btn i {
  font-size: 0.75rem;
}

/* ------------------------------------------------------------------
 * A row from md, two columns from lg
 * ------------------------------------------------------------------ */

@media (min-width: 768px) {
  .cart-title {
    font-size: 2rem;
  }

  /* The same five things core's table columns held, in the same reading order,
     without the horizontal scroller: only the tracks and the area map change. */
  .cart-item {
    grid-template-columns: 96px minmax(0, 1fr) auto 2rem;
    grid-template-areas:
      'thumb body foot remove'
      'note  note note note';
    align-items: center;
    gap: 1.125rem;
    padding: 1rem;
  }

  .cart-item-thumb {
    width: 96px;
  }

  .cart-item-body {
    align-self: center;
  }

  .cart-item-foot {
    gap: 1.5rem;
  }

  .cart-item-total {
    min-width: 5.5rem;
    text-align: right;
  }

  .cart-item-remove {
    margin: 0;
  }

  .cart-item-note {
    padding-left: calc(96px + 1.125rem);
  }
}

@media (min-width: 992px) {
  .cart-layout {
    grid-template-columns: minmax(0, 1fr) 340px;
    gap: 1.5rem;
    align-items: start;
  }

  /* The totals stay on screen while a long cart is scrolled. Offset by the
     header's own height so the panel does not slide under it. */
  .cart-aside {
    position: sticky;
    top: 1.5rem;
  }
}

@media (min-width: 1200px) {
  .cart-layout {
    grid-template-columns: minmax(0, 1fr) 380px;
    gap: 2rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .cart-item,
  .cart-item-total,
  .cart-item-name,
  .cart-item-remove,
  .cart-qty,
  .cart-qty-btn,
  .cart-code,
  .cart-code-row,
  .cart-code-apply,
  .cart-code-clear,
  .cart-back,
  .cart-checkout,
  .cart-empty-btn,
  .cart-accordion-btn.accordion-button::after {
    transition: none;
  }

  .cart-qty-input.is-bumped {
    animation: none;
  }

  /* The row still says it is working; the line simply does not travel. */
  .cart-item.is-busy::before {
    width: 100%;
    animation: none;
    opacity: 0.5;
  }
}

/* ------------------------------------------------------------------
 * Cart page: arrival, hover and change
 *
 * The cart is a task surface, so nothing here is decoration: the page arrives
 * the way the rest of the storefront arrives, and everything after that fires
 * only when something has actually changed. No loops, no scroll-linked motion,
 * nothing that has to finish before the page can be used.
 *
 * Arrival is .simko-arrive rather than .simko-reveal -- the scroll watcher waits
 * for a fifth of a block to enter the viewport, and on a desktop the whole cart
 * is inside it on load, so it would never fire. Both are gated on html.simko-js,
 * set at parse time by simko.js, so with no script -- and under reduced motion,
 * where the class is still set but every rule below is cancelled -- the page is
 * simply there.
 * ------------------------------------------------------------------ */

.simko-js .simko-arrive.cart-head,
.simko-js .simko-arrive.cart-aside,
.simko-js .simko-arrive.cart-empty {
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity 420ms var(--simko-ease),
    transform 420ms var(--simko-ease);
}

/* The summary follows the items rather than landing with them: it is the last
   thing read, and the two columns arriving together on a desktop reads as the
   page being assembled in front of the shopper. */
.simko-js .simko-arrive.cart-aside {
  transition-delay: 180ms;
}

.simko-js .simko-arrive-in.cart-head,
.simko-js .simko-arrive-in.cart-aside,
.simko-js .simko-arrive-in.cart-empty {
  opacity: 1;
  transform: none;
}

/* Rows arrive in reading order. --card-index is set per row by the template;
   the step is small on purpose -- a cart of ten lines must not take a second to
   finish, so the stagger is capped by the number of rows a shopper can see. */
.simko-js .simko-arrive.cart-items .cart-item {
  opacity: 0;
  transform: translateY(12px);
  transition:
    opacity 380ms var(--simko-ease),
    transform 380ms var(--simko-ease);
  transition-delay: calc(60ms + var(--card-index, 0) * 55ms);
}

.simko-js .simko-arrive-in.cart-items .cart-item {
  opacity: 1;
  transform: none;
}

/* The empty cart's one flourish, and it plays once: the bag settles into its
   disc a beat after the card lands, which is the only thing on that screen with
   anything to say. */
.simko-js .simko-arrive.cart-empty .cart-empty-icon {
  transform: scale(0.86);
  transition: transform 480ms var(--simko-ease) 220ms;
}

.simko-js .simko-arrive-in.cart-empty .cart-empty-icon {
  transform: none;
}

/* ------------------------------------------------------------------
 * Hover, on a desktop only
 *
 * Below lg there is no pointer to hover with, and a touch that leaves a row
 * lifted is a row that stays lifted.
 * ------------------------------------------------------------------ */

@media (hover: hover) and (pointer: fine) {
  .cart-item {
    transition:
      border-color var(--simko-speed) var(--simko-ease),
      box-shadow var(--simko-speed) var(--simko-ease),
      transform var(--simko-speed) var(--simko-ease);
  }

  /* Lifted by a pixel and given the storefront's one neutral shadow. Any more
     and a list of rows becomes a list of things that move. */
  .cart-item:hover {
    border-color: #d4d4d4;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.06);
    transform: translateY(-1px);
  }

  /* The picture is the row's own link to the product, so it answers the pointer
     the way the listing card's picture does. */
  .cart-item-thumb img {
    transition: scale var(--simko-speed) var(--simko-ease);
  }

  .cart-item:hover .cart-item-thumb img {
    scale: 1.06;
  }

  /* Arrows lean toward where they go. */
  .cart-checkout i,
  .cart-empty-btn i,
  .cart-back i {
    transition: transform var(--simko-speed) var(--simko-ease);
  }

  .cart-checkout:hover i,
  .cart-empty-btn:hover i {
    transform: translateX(3px);
  }

  .cart-back:hover i {
    transform: translateX(-3px);
  }
}

/* A pressed stepper button gives under the finger. Same treatment the product
   page's stepper has, so the control feels the same in both places. */
.cart-qty-btn:active:not(:disabled) {
  transform: scale(0.9);
}

/* ------------------------------------------------------------------
 * The amounts that moved
 * ------------------------------------------------------------------ */

/* Set for one beat by cartPage() on any amount whose value is not what it was.
   The line total sits beside the stepper that changed it, but the order total is
   below the entire list -- on a phone, off the screen the tap happened on -- so
   the numbers that moved are the ones that say so. */
.cart-item-total.is-changed,
.cart-summary-row [data-simko-cart-total].is-changed {
  animation: simko-cart-changed 780ms var(--simko-ease);
}

@keyframes simko-cart-changed {
  0% {
    color: var(--simko-brand);
    transform: translateY(-3px);
  }

  35% {
    color: var(--simko-brand);
    transform: none;
  }

  100% {
    transform: none;
  }
}

/* The order total is brand red already, so a red flash would say nothing. It
   takes the same beat as a lift and a touch of weight instead. */
.cart-summary-row-final [data-simko-cart-total].is-changed {
  animation: simko-cart-changed-final 780ms var(--simko-ease);
}

@keyframes simko-cart-changed-final {
  0% {
    transform: translateY(-3px) scale(1.06);
  }

  35% {
    transform: none;
  }
}

/* The feedback under a coupon field arrives rather than appearing: it replaces
   nothing, so without this a line of text simply materialises under the input. */
.cart-code-feedback:not(:empty) {
  animation: simko-cart-said 260ms var(--simko-ease);
}

@keyframes simko-cart-said {
  0% {
    opacity: 0;
    transform: translateY(-4px);
  }
}

/* ------------------------------------------------------------------
 * A row on its way out
 *
 * The height is measured and written inline by cartPage() before this class goes
 * on, because there is no height to collapse from otherwise. .cart-item already
 * carries overflow: hidden, which is what lets the contents be squashed rather
 * than spilling as the row closes.
 * ------------------------------------------------------------------ */

.cart-item.is-leaving {
  max-height: 0 !important;
  min-height: 0;
  padding-top: 0;
  padding-bottom: 0;
  border-width: 0;
  opacity: 0;
  transform: translateX(12px);
  transition:
    max-height 260ms var(--simko-ease),
    padding 260ms var(--simko-ease),
    margin 260ms var(--simko-ease),
    opacity 200ms var(--simko-ease),
    transform 260ms var(--simko-ease);
  pointer-events: none;
}

/* Nothing on a row that is closing needs to be working as well. */
.cart-item.is-leaving::before {
  display: none;
}

@media (prefers-reduced-motion: reduce) {
  /* Nothing is hidden waiting to arrive: the page is on screen from the start
     and every arrival rule above is cancelled here rather than in the script,
     so the markup stays identical either way. */
  .simko-js .simko-arrive.cart-head,
  .simko-js .simko-arrive.cart-aside,
  .simko-js .simko-arrive.cart-empty,
  .simko-js .simko-arrive.cart-items .cart-item {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .simko-js .simko-arrive.cart-empty .cart-empty-icon {
    transform: none;
    transition: none;
  }

  .cart-item,
  .cart-item-thumb img {
    transition: none;
  }

  .cart-item:hover {
    box-shadow: none;
    transform: none;
  }

  .cart-item:hover .cart-item-thumb img {
    scale: 1;
  }

  .cart-checkout:hover i,
  .cart-empty-btn:hover i,
  .cart-back:hover i {
    transform: none;
  }

  .cart-qty-btn:active:not(:disabled) {
    transform: none;
  }

  /* An amount that changed still has to be findable, so the beat becomes a
     colour that simply holds and then goes. cartPage() takes the class off. */
  .cart-item-total.is-changed,
  .cart-summary-row [data-simko-cart-total].is-changed {
    animation: none;
    color: var(--simko-brand);
  }

  .cart-summary-row-final [data-simko-cart-total].is-changed {
    animation: none;
  }

  .cart-code-feedback:not(:empty) {
    animation: none;
  }

  /* fold() in cartPage() does not run under reduced motion, so .is-leaving is
     never set and there is nothing to cancel here -- the row is replaced.  */
}

/* ------------------------------------------------------------------
 * Checkout page (.checkout-page)
 *
 * Core's checkout is two Bootstrap columns with no reading order of its own: the
 * details form on the left, and on the right a stack of Shipping Method, Payment
 * Method and the order summary. The three things that have to happen in sequence
 * are split across two columns, and on a phone the summary and its Confirm
 * button land at the very bottom, under a form that is most of a screen tall.
 *
 * Rebuilt as one ordered column of numbered steps with the summary beside it.
 * .checkout-main holds every step in the order it has to be done;
 * .checkout-aside holds the summary and sticks from lg, so the amount and the
 * button stay on screen while the steps are worked through. On a phone it is one
 * column and the summary comes last, which is where a shopper looks after
 * choosing rather than before.
 *
 * Every step is a card on the content ground. The summary is the one surface
 * that is not -- the same #fafafa panel the cart page ends with, which is what
 * the shopper saw one page ago.
 * ------------------------------------------------------------------ */

.checkout-head {
  margin-bottom: 1.25rem;
}

.checkout-title {
  margin: 0;
  font-size: 1.75rem;
  font-weight: 800;
  line-height: 1.15;
  color: var(--simko-ink);
}

/* Says what the page is. Core's H1 stood alone, and the only other line above
   the form was the login link. */
.checkout-head-meta {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0.4rem 0 0;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--simko-ink-muted);
}

.checkout-head-meta i {
  font-size: 0.75rem;
  color: var(--simko-brand);
}

/* ------------------------------------------------------------------
 * Step rail (.checkout-rail)
 *
 * How many steps there are and how far along they are, for a shopper who cannot
 * see past the first one. Three at most, so it fits across 390px without
 * scrolling; the connector is drawn on the item rather than between them, which
 * keeps it out of the markup.
 * ------------------------------------------------------------------ */

.checkout-rail {
  display: flex;
  margin: 0 0 1.25rem;
  padding: 0;
  counter-reset: none;
}

.checkout-rail-step {
  position: relative;
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.35rem;
  min-width: 0;
  text-align: center;
}

/* The line to the step before. Drawn from the circle's edge outwards, so it
   never crosses a number. */
.checkout-rail-step + .checkout-rail-step::before {
  content: '';
  position: absolute;
  top: 0.9rem;
  right: 50%;
  left: -50%;
  margin: 0 1.25rem;
  height: 2px;
  background-color: var(--simko-border);
  transition: background-color var(--simko-speed) var(--simko-ease);
}

.checkout-rail-step.is-done + .checkout-rail-step::before,
.checkout-rail-step.is-current::before {
  background-color: var(--simko-brand-light);
}

.checkout-rail-no {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.8rem;
  height: 1.8rem;
  border-radius: 50%;
  background-color: #fff;
  border: 2px solid var(--simko-border);
  color: var(--simko-ink-muted);
  font-size: 0.8125rem;
  font-weight: 700;
  transition: color var(--simko-speed) var(--simko-ease), border-color var(--simko-speed) var(--simko-ease), background-color var(--simko-speed) var(--simko-ease);
}

/* Both the number and the tick are in the markup and one of them is hidden, so a
   step that settles needs no rewriting. */
.checkout-rail-no i,
.checkout-step-no i {
  display: none;
  font-size: 0.6875rem;
}

.checkout-rail-step.is-done .checkout-digit,
.checkout-step.is-done .checkout-step-no .checkout-digit {
  display: none;
}

.checkout-rail-step.is-done .checkout-rail-no i,
.checkout-step.is-done .checkout-step-no i {
  display: block;
}

.checkout-rail-step.is-current .checkout-rail-no {
  border-color: var(--simko-brand);
  background-color: var(--simko-brand);
  color: #fff;
}

.checkout-rail-step.is-done .checkout-rail-no {
  border-color: var(--simko-brand);
  background-color: var(--simko-brand);
  color: #fff;
}

.checkout-rail-title {
  font-size: 0.6875rem;
  font-weight: 600;
  line-height: 1.3;
  color: var(--simko-ink-muted);
}

.checkout-rail-step.is-current .checkout-rail-title,
.checkout-rail-step.is-done .checkout-rail-title {
  color: var(--simko-ink);
}

/* ------------------------------------------------------------------
 * Layout and steps (.checkout-layout, .checkout-step)
 * ------------------------------------------------------------------ */

.checkout-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.25rem;
}

.checkout-main {
  display: grid;
  gap: 1rem;
  min-width: 0;
}

.checkout-step {
  padding: 1.1rem 1rem 1.25rem;
  border: 1px solid var(--simko-border);
  border-radius: 14px;
  background-color: #fff;
  transition: opacity var(--simko-speed) var(--simko-ease), border-color var(--simko-speed) var(--simko-ease);
}

/* A step whose options cannot be fetched yet is still on the page -- it says
   what it is waiting for -- but it is plainly not the one to work on. Only the
   heading is dimmed: the payment step also holds the order comment, which can be
   written at any point and should not look closed. */
.checkout-step:has(.checkout-methods.is-waiting) .checkout-step-head {
  opacity: 0.55;
}

.checkout-step-head {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  margin-bottom: 1rem;
}

.checkout-step-no {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 50%;
  background-color: var(--simko-tint);
  color: var(--simko-brand);
  font-size: 0.8125rem;
  font-weight: 800;
  transition: color var(--simko-speed) var(--simko-ease), background-color var(--simko-speed) var(--simko-ease);
}

.checkout-step.is-done .checkout-step-no {
  background-color: var(--simko-brand);
  color: #fff;
}

.checkout-step-title {
  margin: 0;
  flex: 1 1 auto;
  min-width: 0;
  font-size: 1.0625rem;
  font-weight: 800;
  color: var(--simko-ink);
}

/* 'Saved', beside the heading of a step that is settled. */
.checkout-step-state {
  flex: none;
  font-size: 0.75rem;
  font-weight: 700;
  color: #1f7a3d;
}

.checkout-step-state:empty {
  display: none;
}

/* ------------------------------------------------------------------
 * Form fields (.checkout-grid, .checkout-field)
 *
 * One grid, one column on a phone and two from md, rather than core's nested
 * Bootstrap rows. .is-wide is for the fields that read badly at half width --
 * a textarea, or a row of choices.
 * ------------------------------------------------------------------ */

.checkout-form {
  min-width: 0;
}

.checkout-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.85rem;
}

.checkout-grid + .checkout-grid,
.checkout-grid + .checkout-block,
.checkout-block + .checkout-grid,
.checkout-block + .checkout-block {
  margin-top: 1.35rem;
}

.checkout-field {
  min-width: 0;
}

.checkout-block {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

/* The details step stacks its blocks -- register, payment address, shipping
   address -- as bare wrappers with no margin of their own, so the shipping
   legend landed hard against the address select above it. The :has() guard is
   what keeps this honest: a wrapper whose fieldset is hidden (shipping, while
   the payment address stands in for it) still occupies a slot in the DOM, and
   a plain `div + div` would space off that empty box. */
.checkout-step-body > div:has(> :not([hidden])) + div:has(> :not([hidden])) {
  margin-top: 1.75rem;
}

/* A fieldset legend cannot be a grid or flex item, so the heading is styled
   rather than positioned. */
.checkout-block-title {
  float: none;
  width: auto;
  margin: 0 0 0.85rem;
  padding: 0;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--simko-ink-muted);
}

.checkout-label {
  display: block;
  margin-bottom: 0.3rem;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--simko-ink);
}

/* Core marks a required field by putting .required on the wrapper and drawing a
   red asterisk before the label; after the words is where it belongs. */
.checkout-field.required > .checkout-label::after {
  content: '*';
  margin-left: 0.2rem;
  color: var(--simko-brand);
}

.checkout-input {
  display: block;
  width: 100%;
  min-height: var(--simko-control-h);
  padding: 0.5rem 0.85rem;
  color: var(--simko-ink);
  font-size: 0.9375rem;
  font-family: inherit;
  line-height: 1.4;
  background-color: #fff;
  border: 1px solid var(--simko-border);
  border-radius: var(--simko-radius);
  transition: border-color var(--simko-speed) var(--simko-ease), box-shadow var(--simko-speed) var(--simko-ease);
}

textarea.checkout-input {
  min-height: 0;
  resize: vertical;
}

.checkout-input::placeholder {
  color: var(--simko-ink-muted);
}

.checkout-input:focus {
  outline: none;
  border-color: var(--simko-brand);
  box-shadow: 0 0 0 3px var(--simko-tint);
}

.checkout-input:disabled {
  background-color: #f5f5f5;
  color: var(--simko-ink-muted);
}

/* The save routes put .is-invalid on the field itself, which Bootstrap draws
   with a background icon inside the field; the border and the ring say it
   without taking room from the value. */
.checkout-input.is-invalid {
  border-color: var(--simko-brand);
  box-shadow: 0 0 0 3px var(--simko-tint);
}

.checkout-error {
  margin-top: 0.3rem;
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--simko-brand);
}

.checkout-error:empty {
  display: none;
}

/* Under a field that is asking for something the shopper may not see the point
   of. Sits above the error line, so a field that fails still reads top-down:
   label, control, why it is wanted, what is wrong with it. */
.checkout-hint {
  margin: 0.3rem 0 0;
  font-size: 0.75rem;
  line-height: 1.4;
  color: var(--simko-ink-muted);
}

/* Fields a captcha extension prints inside the form, which the child theme
   cannot put its own class on. The contact page mounts the same captcha, so it
   is named here rather than restyled a second time under .info-page. */
.checkout-page .form-control,
.checkout-page .form-select,
.info-page .form-control,
.info-page .form-select {
  min-height: var(--simko-control-h);
  border-color: var(--simko-border);
  border-radius: var(--simko-radius);
  font-size: 0.9375rem;
}

.checkout-page .form-control:focus,
.checkout-page .form-select:focus,
.info-page .form-control:focus,
.info-page .form-select:focus {
  border-color: var(--simko-brand);
  box-shadow: 0 0 0 3px var(--simko-tint);
}

.checkout-captcha img {
  max-width: 100%;
  height: auto;
  border-radius: var(--simko-radius);
}

/* ------------------------------------------------------------------
 * Tiles (.checkout-tiles)
 *
 * Register-or-guest, and new-or-saved address. Core gave each of these two
 * inline radios; they are the decisions that change what the rest of the step
 * asks for, and a 12px dot is a poor control for that. The whole tile is the
 * target.
 * ------------------------------------------------------------------ */

.checkout-tiles {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.6rem;
  margin-bottom: 1.15rem;
}

.checkout-tile {
  position: relative;
  min-width: 0;
}

/* z-index, because a transform on a later sibling would otherwise paint over
   this: a transformed element joins the same painting stage as a positioned one
   and, with both at z-index auto, DOM order decides. The press feedback below is
   a transform on the wrapper for the same reason -- when the label rose above
   the input mid-press, mousedown and mouseup landed on different elements and no
   click was dispatched at all, which is why the tiles took several tries. */
.checkout-tile-input {
  position: absolute;
  z-index: 1;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.checkout-tile-label {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  height: 100%;
  min-height: var(--simko-touch);
  padding: 0.7rem 0.85rem;
  background-color: #fff;
  border: 1px solid var(--simko-border);
  border-radius: 12px;
  cursor: pointer;
  transition: color var(--simko-speed) var(--simko-ease), border-color var(--simko-speed) var(--simko-ease), background-color var(--simko-speed) var(--simko-ease);
}

.checkout-tile-name {
  font-size: 0.875rem;
  font-weight: 700;
  color: var(--simko-ink);
}

.checkout-tile-note {
  font-size: 0.6875rem;
  line-height: 1.35;
  color: var(--simko-ink-muted);
}

.checkout-tile-input:checked + .checkout-tile-label {
  border-color: var(--simko-brand);
  background-color: var(--simko-tint);
}

.checkout-tile-input:checked + .checkout-tile-label .checkout-tile-name {
  color: var(--simko-brand);
}

.checkout-tile-input:focus-visible + .checkout-tile-label {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

.checkout-tile-input:disabled + .checkout-tile-label {
  cursor: default;
  opacity: 0.7;
}

/* ------------------------------------------------------------------
 * Switches and choices (.checkout-switch, .checkout-choices)
 * ------------------------------------------------------------------ */

.checkout-consents {
  display: grid;
  gap: 0.35rem;
  margin: 1.25rem 0 1rem;
}

.checkout-switch {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  min-height: var(--simko-touch);
}

/* Bootstrap's .form-switch is a background-image track that it recolours to its
   own primary. Drawn here instead, in the theme's colour and at a size a thumb
   can find. */
.checkout-switch-input {
  position: relative;
  flex: none;
  appearance: none;
  -webkit-appearance: none;
  width: 2.5rem;
  height: 1.4rem;
  margin: 0;
  border: 0;
  border-radius: 999px;
  background-color: #dcdcdc;
  cursor: pointer;
  transition: background-color var(--simko-speed) var(--simko-ease);
}

.checkout-switch-input::after {
  content: '';
  position: absolute;
  top: 0.2rem;
  left: 0.2rem;
  width: 1rem;
  height: 1rem;
  border-radius: 50%;
  background-color: #fff;
  transition: transform var(--simko-speed) var(--simko-ease);
}

.checkout-switch-input:checked {
  background-color: var(--simko-brand);
}

.checkout-switch-input:checked::after {
  transform: translateX(1.1rem);
}

.checkout-switch-input:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

.checkout-switch-input:disabled {
  cursor: default;
  opacity: 0.6;
}

.checkout-switch-label {
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--simko-ink);
  cursor: pointer;
}

.checkout-switch-label a {
  color: var(--simko-brand);
  font-weight: 700;
}

/* Nothing can be confirmed until this is ticked, so it is set apart from the
   two consents above it rather than reversed to the far right as core's was. */
.checkout-agree {
  display: flex;
  align-items: center;
  gap: 0.65rem;
  min-height: var(--simko-touch);
  margin-top: 1rem;
  padding: 0.6rem 0.85rem;
  border: 1px solid var(--simko-border);
  border-radius: 12px;
  background-color: var(--simko-tint);
}

/* A custom field's own radio or checkbox values, as chips -- the same control
   the product page's options use. */
.checkout-choices {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.checkout-choice {
  position: relative;
}

.checkout-choice-input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.checkout-choice-label {
  display: flex;
  align-items: center;
  min-height: var(--simko-touch);
  padding: 0.4rem 0.9rem;
  color: var(--simko-ink);
  font-size: 0.875rem;
  background-color: #fff;
  border: 1px solid var(--simko-border);
  border-radius: 999px;
  cursor: pointer;
  transition: color var(--simko-speed) var(--simko-ease), border-color var(--simko-speed) var(--simko-ease), background-color var(--simko-speed) var(--simko-ease);
}

.checkout-choice-input:checked + .checkout-choice-label {
  color: var(--simko-brand);
  border-color: var(--simko-brand);
  background-color: var(--simko-tint);
  font-weight: 600;
}

.checkout-choice-input:focus-visible + .checkout-choice-label {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

/* ------------------------------------------------------------------
 * Buttons and notes (.checkout-submit, .checkout-upload)
 * ------------------------------------------------------------------ */

.checkout-submit {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  width: 100%;
  min-height: 3rem;
  padding: 0 1.25rem;
  border: 0;
  border-radius: var(--simko-radius);
  background-color: var(--simko-brand);
  color: #fff;
  font-size: 0.9375rem;
  font-weight: 700;
  transition: background-color var(--simko-speed) var(--simko-ease), transform var(--simko-speed) var(--simko-ease);
}

.checkout-submit:hover:not(:disabled) {
  background-color: var(--simko-brand-dark);
  color: #fff;
}

.checkout-submit:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

.checkout-submit i {
  font-size: 0.75rem;
}

/* While the answer is on its way. Core swapped the label for a spinner, which
   changed the button's width mid-press. */
.checkout-submit.is-working {
  background-color: var(--simko-brand-light);
  cursor: progress;
}

.checkout-upload {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: var(--simko-touch);
  padding: 0 1rem;
  border: 1px solid var(--simko-border);
  border-radius: var(--simko-radius);
  background-color: #fff;
  color: var(--simko-ink);
  font-size: 0.875rem;
  font-weight: 600;
  transition: border-color var(--simko-speed) var(--simko-ease), color var(--simko-speed) var(--simko-ease);
}

.checkout-upload:hover,
.checkout-upload:focus-visible {
  border-color: var(--simko-brand);
  color: var(--simko-brand);
}

/* Where a form's answer lands. Core's went to #alert at the top of the document,
   which on a phone is a screen away from the button that was pressed. */
.checkout-form-note {
  margin: 0.75rem 0 0;
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.45;
}

.checkout-form-note:empty {
  display: none;
}

.checkout-form-note.is-error {
  color: var(--simko-brand);
}

.checkout-form-note.is-success {
  color: #1f7a3d;
}

/* The login link, for the shopper who is in the wrong place.

   Not a flex row: the sentence arrives from the language file with a link inside
   it, and flex would make that link a sibling item of the words around it --
   which reorders the sentence. */
.checkout-signin {
  margin: 0 0 1.15rem;
  padding: 0.7rem 0.85rem;
  border-radius: 12px;
  background-color: #fafafa;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--simko-ink-muted);
}

.checkout-signin i {
  margin-right: 0.35rem;
  color: var(--simko-brand);
}

.checkout-signin a {
  color: var(--simko-brand);
  font-weight: 700;
}

/* ------------------------------------------------------------------
 * Method choosers (.checkout-methods)
 *
 * Core showed a readonly field and a Choose button, which fetched the options
 * and built a modal to pick from -- two taps and a layer over the page to choose
 * between what is usually one option. The options are cards here, and picking
 * one posts it.
 * ------------------------------------------------------------------ */

.checkout-methods-hint {
  margin: 0 0 0.7rem;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--simko-ink-muted);
}

.checkout-methods-hint:empty {
  display: none;
}

.checkout-methods-list {
  display: grid;
  gap: 0.55rem;
}

.checkout-methods-list:empty {
  display: none;
}

.checkout-method {
  position: relative;
  display: block;
  margin: 0;
  min-width: 0;
}

.checkout-method-input {
  position: absolute;
  z-index: 1;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.checkout-method-frame {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-height: 3.5rem;
  padding: 0.7rem 0.9rem;
  background-color: #fff;
  border: 1px solid var(--simko-border);
  border-radius: 12px;
  cursor: pointer;
  transition: border-color var(--simko-speed) var(--simko-ease), background-color var(--simko-speed) var(--simko-ease);
}

.checkout-method-tick {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.25rem;
  height: 1.25rem;
  border: 1.5px solid var(--simko-border);
  border-radius: 50%;
  color: transparent;
  font-size: 0.625rem;
  transition: color var(--simko-speed) var(--simko-ease), border-color var(--simko-speed) var(--simko-ease), background-color var(--simko-speed) var(--simko-ease);
}

.checkout-method-body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}

.checkout-method-name {
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--simko-ink);
}

/* The carrier behind the option, shown only when there is more than one of
   them: with a single carrier it repeats what the option already says. */
.checkout-method-carrier {
  font-size: 0.6875rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--simko-ink-muted);
}

.checkout-method-cost {
  flex: none;
  font-size: 0.9375rem;
  font-weight: 800;
  color: var(--simko-ink);
}

/* The payment scheme's own mark, at the far end of the row.

   FPX Brand Guideline v1.2 sets a floor of 22.6px tall by 67.9px wide for the
   standard logo and asks for clear space around it the height of the wordmark's
   'X' -- about 17px at this size. The 24px height clears the floor; the margin
   and the frame's own padding give the gutter. It is never scaled below that,
   so on a narrow row the name wraps instead. */
.checkout-method-logo {
  flex: none;
  display: flex;
  align-items: center;
  margin-left: 1.125rem;
}

.checkout-method-logo img {
  display: block;
  width: auto;
  height: 24px;
}

.checkout-method-input:checked + .checkout-method-frame {
  border-color: var(--simko-brand);
  background-color: var(--simko-tint);
}

.checkout-method-input:checked + .checkout-method-frame .checkout-method-tick {
  background-color: var(--simko-brand);
  border-color: var(--simko-brand);
  color: #fff;
}

.checkout-method-input:checked + .checkout-method-frame .checkout-method-cost {
  color: var(--simko-brand);
}

.checkout-method-input:focus-visible + .checkout-method-frame {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

/* The method already in the session, before its options have arrived, and all
   there is to see with no script running. */
.checkout-method-chosen {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
  font-size: 0.9375rem;
  font-weight: 600;
  color: var(--simko-ink);
}

.checkout-method-chosen i {
  color: var(--simko-brand);
}

/* A carrier that cannot quote for this address, where its options would be. */
.checkout-method-error {
  margin: 0;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--simko-brand);
}

.checkout-methods-note {
  margin: 0.7rem 0 0;
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.45;
  color: var(--simko-ink-muted);
}

.checkout-methods-note:empty {
  display: none;
}

.checkout-methods-note.is-error {
  color: var(--simko-brand);
}

.checkout-methods-note a {
  color: var(--simko-brand);
}

/* The waiting line is the only thing in the step, so it does not need the weight
   of a message about something that went wrong. */
.checkout-methods.is-waiting .checkout-methods-note {
  margin-top: 0;
  font-weight: 500;
}

/* ------------------------------------------------------------------
 * Order comment (.checkout-comment)
 * ------------------------------------------------------------------ */

.checkout-comment {
  margin-top: 1.35rem;
}

.checkout-comment-note {
  margin: 0.4rem 0 0;
  font-size: 0.75rem;
  font-weight: 600;
  color: #1f7a3d;
}

.checkout-comment-note:empty {
  display: none;
}

.checkout-comment-note.is-error {
  color: var(--simko-brand);
}

/* ------------------------------------------------------------------
 * Summary panel (.checkout-summary)
 *
 * The cart page's totals panel, with the order's lines above it. It is the one
 * surface on the page that is not the content ground, so it reads as the thing
 * you act from rather than as a fourth step.
 * ------------------------------------------------------------------ */

.checkout-aside {
  min-width: 0;
}

#checkout-confirm {
  transition: opacity var(--simko-speed) var(--simko-ease);
}

/* While the panel is being fetched. Also stops a second press of Confirm
   landing on a button that is about to be replaced. */
#checkout-confirm.is-busy {
  opacity: 0.55;
  pointer-events: none;
}

/* An address was edited after it was saved. What the panel shows is the charge
   worked out for the address as it was, and the server would still take it, so
   the whole panel -- Confirm included -- is put out of reach until Continue. */
#checkout-confirm.is-stale {
  opacity: 0.5;
  pointer-events: none;
}

.checkout-aside-note {
  margin: 0.65rem 0 0;
  padding: 0.6rem 0.75rem;
  border-radius: 10px;
  background-color: var(--simko-tint);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.45;
  color: var(--simko-brand);
  text-align: center;
}

.checkout-aside-note:empty {
  display: none;
}

.checkout-summary {
  padding: 1.125rem 1.25rem 1.25rem;
  border: 1px solid var(--simko-border);
  border-radius: 14px;
  background-color: #fafafa;
}

.checkout-summary-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.9rem;
}

.checkout-summary-title {
  margin: 0;
  font-size: 1rem;
  font-weight: 800;
  color: var(--simko-ink);
}

/* One tap back to the cart. Core's only route back was the browser's own back
   button. */
.checkout-summary-edit {
  flex: none;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--simko-ink-muted);
  text-decoration: none;
  transition: color var(--simko-speed) var(--simko-ease);
}

.checkout-summary-edit:hover,
.checkout-summary-edit:focus-visible {
  color: var(--simko-brand);
}

.checkout-summary-items {
  display: grid;
  gap: 0.7rem;
  margin: 0 0 0.9rem;
  padding-bottom: 0.9rem;
  border-bottom: 1px solid var(--simko-border);
}

.checkout-summary-item {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  min-width: 0;
}

/* The amount, as a chip rather than as '2x' run into the product's name the way
   core's table cell had it. */
.checkout-summary-qty {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.05rem;
  min-width: 1.9rem;
  height: 1.6rem;
  padding: 0 0.35rem;
  background-color: #fff;
  border: 1px solid var(--simko-border);
  border-radius: 6px;
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--simko-ink);
}

.checkout-summary-body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}

.checkout-summary-name {
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.35;
  color: var(--simko-ink);
  text-decoration: none;
  /* Product names in this catalogue run long, and a third line pushes the
     totals below it out of the panel's first screen. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.checkout-summary-name:hover,
.checkout-summary-name:focus-visible {
  color: var(--simko-brand);
  text-decoration: none;
}

.checkout-summary-meta {
  display: flex;
  flex-direction: column;
  font-size: 0.6875rem;
  line-height: 1.4;
  color: var(--simko-ink-muted);
}

.checkout-summary-total {
  flex: none;
  font-size: 0.8125rem;
  font-weight: 700;
  color: var(--simko-ink);
}

.checkout-summary-rows {
  margin: 0 0 1rem;
  font-size: 0.875rem;
}

.checkout-summary-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.25rem 0;
  color: var(--simko-ink-muted);
}

/* The last line is the amount that will be charged. */
.checkout-summary-row-final {
  margin-top: 0.5rem;
  padding-top: 0.65rem;
  border-top: 1px solid var(--simko-border);
  color: var(--simko-ink);
  font-size: 1.125rem;
  font-weight: 800;
}

.checkout-summary-row-final span:last-child {
  color: var(--simko-brand);
}

/* ------------------------------------------------------------------
 * Confirm button (#checkout-payment)
 *
 * Whatever the payment extension renders. The child theme has no say over that
 * markup -- it arrives with the summary on every reload -- so the button is
 * styled by what it is rather than by a class.
 * ------------------------------------------------------------------ */

.checkout-pay .text-end,
.checkout-pay > div {
  text-align: center;
}

/* Bank Transfer and Cheque bring a fieldset, a legend, and a panel of details
   built from Bootstrap's border utilities -- which carry !important, so they are
   steered by redefining the variables they read rather than by out-shouting
   them. Cheaper than forking a payment extension's template, and it catches the
   next extension that renders the same shape. */
.checkout-pay {
  --bs-border-color: var(--simko-border);
  --bs-border-radius: 10px;

  margin-top: 1.1rem;
  padding-top: 1.1rem;
  border-top: 1px solid var(--simko-border);
}

.checkout-pay fieldset {
  margin: 0;
  padding: 0;
  border: 0;
}

/* A legend is a 1.5rem heading by default -- larger than the panel's own title,
   for something that is a note under the total. */
.checkout-pay legend {
  float: none;
  width: auto;
  margin: 0 0 0.5rem;
  padding: 0;
  /* Core's stylesheet rules a line under every legend, which here fell between
     the heading and the sentence it introduces. */
  border-bottom: 0;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--simko-ink-muted);
}

.checkout-pay fieldset p {
  margin: 0 0 0.5rem;
  font-size: 0.8125rem;
  line-height: 1.5;
  text-align: left;
  color: var(--simko-ink-muted);
}

/* The instruction above the account details, which the extension sets in bold
   body text at the width of a phone. */
.checkout-pay fieldset > p b,
.checkout-pay fieldset > p strong {
  font-weight: 600;
  color: var(--simko-ink);
}

/* The account details themselves: the one thing on the panel to be copied, so
   they sit on their own surface. */
.checkout-pay fieldset .border {
  background-color: #fff;
  padding: 0.85rem 0.9rem;
}

.checkout-pay fieldset .border p:last-child {
  margin-bottom: 0;
}

/* A payment extension that renders nothing but a button needs no rule above it
   -- there is nothing to separate the button from. */
.checkout-pay:not(:has(fieldset)) {
  margin-top: 1rem;
  padding-top: 0;
  border-top: 0;
}

.checkout-pay button,
.checkout-pay .btn,
.checkout-pay-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  width: 100%;
  min-height: 3rem;
  padding: 0 1.25rem;
  border: 0;
  border-radius: var(--simko-radius);
  background-color: var(--simko-brand);
  color: #fff;
  font-size: 0.9375rem;
  font-weight: 700;
  transition: background-color var(--simko-speed) var(--simko-ease);
}

.checkout-pay button:hover:not(:disabled),
.checkout-pay .btn:hover:not(:disabled) {
  background-color: var(--simko-brand-dark);
  color: #fff;
}

.checkout-pay button:focus-visible,
.checkout-pay .btn:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

.checkout-pay button:disabled,
.checkout-pay .btn:disabled,
.checkout-pay-btn:disabled {
  background-color: #d8d8d8;
  color: #fff;
  cursor: not-allowed;
}

/* Says which step is still in the way. Core's disabled button gave no reason. */
.checkout-pay-note {
  margin: 0.65rem 0 0;
  font-size: 0.75rem;
  line-height: 1.45;
  color: var(--simko-ink-muted);
  text-align: center;
}

/* ------------------------------------------------------------------
 * Two columns from lg
 * ------------------------------------------------------------------ */

@media (min-width: 768px) {
  .checkout-title {
    font-size: 2rem;
  }

  .checkout-rail-title {
    font-size: 0.8125rem;
  }

  /* Left-aligned and capped rather than spread across the whole content width:
     the rail belongs to the column of steps under it, not to the summary beside
     them, and three labels a third of a page apart stop reading as one line. */
  .checkout-rail {
    max-width: 26rem;
  }

  .checkout-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem 1.25rem;
  }

  .checkout-field.is-wide {
    grid-column: 1 / -1;
  }

  .checkout-step {
    padding: 1.35rem 1.5rem 1.6rem;
  }

  /* A full-width button under a two-column grid reads as a page action rather
     than as the end of the step. */
  .checkout-submit {
    width: auto;
    min-width: 12rem;
  }
}

@media (min-width: 992px) {
  .checkout-layout {
    grid-template-columns: minmax(0, 1fr) 360px;
    gap: 1.5rem;
    align-items: start;
  }

  /* The amount and the Confirm button stay on screen while the steps are worked
     through. Offset the way the cart page's panel is. */
  .checkout-aside {
    position: sticky;
    top: 1.5rem;
  }
}

@media (min-width: 1200px) {
  .checkout-layout {
    grid-template-columns: minmax(0, 1fr) 380px;
    gap: 2rem;
  }
}

/* ------------------------------------------------------------------
 * Checkout page: arrival, hover and change
 *
 * Three jobs, in the order a shopper meets them. The page arrives in reading
 * order, so the step to start on is the one that settles first. What can be
 * pressed answers a pointer. And a step that settles, or a total that moves,
 * says so -- on a wide screen the summary is off to the side of whatever was
 * pressed, and without a beat there is nothing to connect the two.
 *
 * Everything is gated on html.simko-js, set at parse time, so with no script the
 * page is simply there. The whole section is cancelled under
 * prefers-reduced-motion at the end, in CSS rather than in checkoutPage(), so
 * the markup is the same either way.
 * ------------------------------------------------------------------ */

.simko-js .simko-arrive.checkout-head,
.simko-js .simko-arrive.checkout-rail,
.simko-js .simko-arrive.checkout-step,
.simko-js .simko-arrive.checkout-aside {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 420ms var(--simko-ease), transform 420ms var(--simko-ease);
}

/* The steps come in one after another, so the list reads downwards rather than
   landing as one block -- the same --card-index the cart's rows use. */
.simko-js .simko-arrive.checkout-step {
  transition-delay: calc(80ms + var(--card-index, 0) * 70ms);
}

/* Last, because it is the answer to the steps rather than part of them. */
.simko-js .simko-arrive.checkout-aside {
  transition-delay: 220ms;
}

.simko-js .simko-arrive-in.checkout-head,
.simko-js .simko-arrive-in.checkout-rail,
.simko-js .simko-arrive-in.checkout-step,
.simko-js .simko-arrive-in.checkout-aside {
  opacity: 1;
  transform: none;
}

/* ------------------------------------------------------------------
 * Hover, for a pointer that can hover. A finger cannot, and a :hover rule that
 * fires on tap leaves the last thing pressed looking half-pressed.
 * ------------------------------------------------------------------ */

@media (hover: hover) and (pointer: fine) {
  .checkout-tile-input:hover:not(:disabled) + .checkout-tile-label,
  .checkout-method-input:hover + .checkout-method-frame,
  .checkout-choice-input:hover + .checkout-choice-label {
    border-color: var(--simko-brand);
  }

  .checkout-method-input:hover + .checkout-method-frame .checkout-method-tick {
    border-color: var(--simko-brand);
  }

  .checkout-submit:hover:not(:disabled) {
    transform: translateY(-1px);
  }

  .checkout-pay button:hover:not(:disabled),
  .checkout-pay .btn:hover:not(:disabled) {
    transform: translateY(-1px);
  }
}

/* Presses answer everywhere, pointer or finger: the control gives a little under
   what is on it and comes back. */
.checkout-submit:active:not(:disabled),
.checkout-pay button:active:not(:disabled),
.checkout-pay .btn:active:not(:disabled) {
  transform: scale(0.99);
}

/* The whole card gives, rather than the frame inside it: transforming a sibling
   of the input that covers the card moves that sibling above the input for the
   length of the press, and a press that starts on one element and ends on
   another is not a click. */
.checkout-method:has(.checkout-method-input:active),
.checkout-tile:has(.checkout-tile-input:active:not(:disabled)) {
  transform: scale(0.99);
}

.checkout-method,
.checkout-tile {
  transition: transform var(--simko-speed) var(--simko-ease);
}

.checkout-method-frame,
.checkout-tile-label {
  transition: color var(--simko-speed) var(--simko-ease), border-color var(--simko-speed) var(--simko-ease), background-color var(--simko-speed) var(--simko-ease), transform var(--simko-speed) var(--simko-ease);
}

/* ------------------------------------------------------------------
 * Change
 * ------------------------------------------------------------------ */

/* The tick that replaces a step's number. Small enough to read as the number
   turning into a tick rather than as something new appearing. */
.checkout-step.is-done .checkout-step-no i,
.checkout-rail-step.is-done .checkout-rail-no i {
  animation: simko-checkout-tick 380ms var(--simko-ease);
}

@keyframes simko-checkout-tick {
  0% {
    opacity: 0;
    transform: scale(0.4);
  }

  55% {
    transform: scale(1.25);
  }

  100% {
    opacity: 1;
    transform: scale(1);
  }
}

/* The summary, just replaced. checkoutPage() sets .is-fresh after the markup
   lands and the animation runs once; the class stays until the next reload,
   which restarts it. */
#checkout-confirm.is-fresh .checkout-summary {
  animation: simko-checkout-fresh 460ms var(--simko-ease);
}

@keyframes simko-checkout-fresh {
  0% {
    opacity: 0.35;
    transform: translateY(6px);
  }

  100% {
    opacity: 1;
    transform: none;
  }
}

/* While the options are on their way, or a choice is being saved. The sweep is
   the cart page's, over the list rather than over a row. */
.checkout-methods.is-loading .checkout-methods-note {
  animation: simko-checkout-waiting 1.1s var(--simko-ease) infinite;
}

@keyframes simko-checkout-waiting {
  0%,
  100% {
    opacity: 1;
  }

  50% {
    opacity: 0.45;
  }
}

.checkout-methods.is-saving .checkout-methods-list {
  position: relative;
  overflow: hidden;
}

.checkout-methods.is-saving .checkout-methods-list::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 40%;
  background-image: linear-gradient(90deg, transparent, rgba(218, 34, 41, 0.09), transparent);
  animation: simko-cart-working 900ms var(--simko-ease) infinite;
  pointer-events: none;
}

/* A step that cannot be worked on yet fades to its dimmed heading rather than
   arriving already dim, so a step that unlocks is seen to unlock. */
.checkout-step-head {
  transition: opacity 300ms var(--simko-ease);
}

@media (prefers-reduced-motion: reduce) {
  .simko-js .simko-arrive.checkout-head,
  .simko-js .simko-arrive.checkout-rail,
  .simko-js .simko-arrive.checkout-step,
  .simko-js .simko-arrive.checkout-aside {
    opacity: 1;
    transform: none;
    transition: none;
    transition-delay: 0s;
  }

  .checkout-step,
  .checkout-step-head,
  .checkout-method,
  .checkout-method-frame,
  .checkout-tile,
  .checkout-tile-label,
  .checkout-choice-label,
  .checkout-submit,
  .checkout-switch-input,
  .checkout-switch-input::after,
  .checkout-rail-no,
  .checkout-rail-step + .checkout-rail-step::before,
  .checkout-step-no,
  .checkout-input,
  .checkout-summary-edit,
  #checkout-confirm,
  .checkout-pay button,
  .checkout-pay .btn {
    transition: none;
  }

  /* Presses and hovers still answer, with colour rather than with movement --
     both are already colour changes above; only the shift is dropped. */
  .checkout-submit:hover:not(:disabled),
  .checkout-submit:active:not(:disabled),
  .checkout-method:has(.checkout-method-input:active),
  .checkout-tile:has(.checkout-tile-input:active:not(:disabled)),
  .checkout-pay button:hover:not(:disabled),
  .checkout-pay button:active:not(:disabled),
  .checkout-pay .btn:hover:not(:disabled),
  .checkout-pay .btn:active:not(:disabled) {
    transform: none;
  }

  .checkout-step.is-done .checkout-step-no i,
  .checkout-rail-step.is-done .checkout-rail-no i,
  #checkout-confirm.is-fresh .checkout-summary,
  .checkout-methods.is-loading .checkout-methods-note {
    animation: none;
  }

  .checkout-methods.is-saving .checkout-methods-list::after {
    display: none;
  }
}

/* ==================================================================
 * Success page (.success-page)
 *
 * Core's success page is an h1 and a paragraph, the same shape whether an order
 * was placed or a contact form was sent. The order case gets a page of its own
 * here: a hero that names the order, then the things a shopper does next --
 * pay, if the order is waiting on a bank transfer, then wait, then check what
 * is coming and where it is going.
 *
 * The reading order is the same on every width. From lg the two address cards
 * move out to a side column, because they are reference rather than sequence,
 * and the sequence should not be broken up by them.
 *
 * The pages with no order (contact, GDPR, logout, returns) render the hero and
 * nothing else, which is what they had before with a mark and a button added.
 * ================================================================== */

.success-page {
  padding-bottom: 3rem;
}

/* ------------------------------------------------------------------
 * Hero (.success-hero)
 * ------------------------------------------------------------------ */

.success-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 2rem 1.1rem 1.75rem;
  border: 1px solid var(--simko-border);
  border-radius: 16px;
  background-image: linear-gradient(180deg, var(--simko-tint), #fff 62%);
  text-align: center;
}

/* The tick. It is the whole message of the page, so it is the largest thing on
   it after the heading. */
.success-mark {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 50%;
  background-color: var(--simko-brand);
  color: #fff;
  font-size: 1.375rem;
}

.success-title {
  margin: 1rem 0 0;
  font-size: 1.5rem;
  font-weight: 800;
  color: var(--simko-ink);
}

.success-lead {
  max-width: 46ch;
  margin: 0.6rem 0 0;
  color: var(--simko-ink-muted);
  font-size: 0.9375rem;
}

/* Core's text_message is a stack of paragraphs of prose with links in it. It is
   left as it is and only given a width to read at. */
.success-message {
  max-width: 56ch;
  margin: 0.6rem 0 0;
  color: var(--simko-ink-muted);
  font-size: 0.9375rem;
}

.success-message p {
  margin: 0 0 0.5rem;
}

.success-message p:last-child {
  margin-bottom: 0;
}

.success-message a {
  color: var(--simko-brand);
  font-weight: 600;
}

/* The order number, the date and the total: the three things a shopper writes
   down. Each is a term over its value so the pair reads on a phone. */
.success-chips {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem;
  margin: 1.25rem 0 0;
}

.success-chip {
  min-width: 8.5rem;
  padding: 0.6rem 0.9rem;
  border: 1px solid var(--simko-border);
  border-radius: 12px;
  background-color: #fff;
}

.success-chip dt {
  color: var(--simko-ink-muted);
  font-size: 0.6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.success-chip dd {
  margin: 0.15rem 0 0;
  color: var(--simko-ink);
  font-size: 1rem;
  font-weight: 800;
}

.success-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.6rem;
  margin-top: 1.35rem;
}

.success-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: var(--simko-touch);
  padding: 0.5rem 1.4rem;
  border: 1px solid var(--simko-border);
  border-radius: var(--simko-radius);
  background-color: #fff;
  color: var(--simko-ink);
  font-size: 0.9375rem;
  font-weight: 700;
  text-decoration: none;
  transition: background-color var(--simko-speed) var(--simko-ease), border-color var(--simko-speed) var(--simko-ease), color var(--simko-speed) var(--simko-ease);
}

.success-btn.is-primary {
  border-color: var(--simko-brand);
  background-color: var(--simko-brand);
  color: #fff;
}

.success-btn:hover,
.success-btn:focus-visible {
  border-color: var(--simko-brand);
  color: var(--simko-brand);
  text-decoration: none;
}

.success-btn.is-primary:hover,
.success-btn.is-primary:focus-visible {
  border-color: var(--simko-brand-dark);
  background-color: var(--simko-brand-dark);
  color: #fff;
}

.success-btn:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

/* ------------------------------------------------------------------
 * Layout and cards (.success-layout, .success-card)
 * ------------------------------------------------------------------ */

.success-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.25rem;
  margin-top: 1.25rem;
}

.success-main,
.success-side {
  display: grid;
  align-content: start;
  gap: 1rem;
  min-width: 0;
}

.success-card {
  padding: 1.1rem 1rem 1.25rem;
  border: 1px solid var(--simko-border);
  border-radius: 14px;
  background-color: #fff;
}

/* The one card that is asking for something rather than reporting it. */
.success-card.is-action {
  border-color: var(--simko-brand);
  background-color: var(--simko-tint);
}

.success-card-title {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 0.85rem;
  font-size: 1.0625rem;
  font-weight: 800;
  color: var(--simko-ink);
}

.success-card.is-action .success-card-title i {
  color: var(--simko-brand);
  font-size: 0.9375rem;
}

.success-card-note {
  margin: -0.4rem 0 1rem;
  color: var(--simko-ink-muted);
  font-size: 0.875rem;
}

/* ------------------------------------------------------------------
 * Bank transfer (.success-pay)
 * ------------------------------------------------------------------ */

.success-pay {
  display: grid;
  gap: 0.75rem;
}

.success-pay-block {
  padding: 0.85rem 0.9rem;
  border: 1px solid var(--simko-border);
  border-radius: 12px;
  background-color: #fff;
}

.success-pay-label {
  display: block;
  margin-bottom: 0.35rem;
  color: var(--simko-ink-muted);
  font-size: 0.6875rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* Account numbers are read a digit at a time and compared against a banking
   app, which is the one place on this storefront a tabular font earns its
   keep. */
.success-pay-lines {
  margin: 0;
  color: var(--simko-ink);
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.6;
  font-variant-numeric: tabular-nums;
}

.success-pay-ref {
  margin: 0;
  color: var(--simko-brand);
  font-size: 1.25rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

/* ------------------------------------------------------------------
 * What happens next (.success-steps)
 * ------------------------------------------------------------------ */

.success-steps {
  display: grid;
  gap: 0.9rem;
  margin: 0;
}

.success-step {
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
}

.success-step-no {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 50%;
  background-color: var(--simko-tint);
  color: var(--simko-brand);
  font-size: 0.8125rem;
  font-weight: 800;
}

.success-step-body {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.success-step-title {
  color: var(--simko-ink);
  font-size: 0.9375rem;
  font-weight: 700;
}

.success-step-note {
  color: var(--simko-ink-muted);
  font-size: 0.8125rem;
  /* An email address is one unbroken word and will otherwise widen the card
     past the viewport on a phone. */
  overflow-wrap: anywhere;
}

/* ------------------------------------------------------------------
 * Items and totals (.success-items, .success-totals)
 * ------------------------------------------------------------------ */

.success-items {
  display: grid;
  gap: 0.85rem;
  margin: 0;
}

.success-item {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.success-item-thumb {
  position: relative;
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 3.25rem;
  height: 3.25rem;
  border: 1px solid var(--simko-border);
  border-radius: 10px;
  background-color: #fff;
  overflow: hidden;
}

.success-item-thumb img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* The quantity rides on the picture rather than taking a column of its own,
   which on a phone is the difference between the name wrapping and not. */
.success-item-qty {
  position: absolute;
  right: -0.35rem;
  bottom: -0.35rem;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 1.35rem;
  height: 1.35rem;
  padding: 0 0.3rem;
  border-radius: 999px;
  background-color: var(--simko-brand);
  color: #fff;
  font-size: 0.6875rem;
  font-weight: 800;
}

.success-item-body {
  flex: 1 1 auto;
  min-width: 0;
}

.success-item-name {
  color: var(--simko-ink);
  font-size: 0.9375rem;
  font-weight: 600;
  text-decoration: none;
}

a.success-item-name:hover,
a.success-item-name:focus-visible {
  color: var(--simko-brand);
  text-decoration: none;
}

.success-item-total {
  flex: none;
  color: var(--simko-ink);
  font-size: 0.9375rem;
  font-weight: 700;
}

.success-totals {
  margin: 1.1rem 0 0;
  padding-top: 0.9rem;
  border-top: 1px solid var(--simko-border);
}

.success-total {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.4rem;
}

.success-total dt {
  color: var(--simko-ink-muted);
  font-size: 0.875rem;
  font-weight: 500;
}

.success-total dd {
  margin: 0;
  color: var(--simko-ink);
  font-size: 0.875rem;
  font-weight: 600;
}

.success-total.is-final {
  margin-bottom: 0;
  padding-top: 0.5rem;
  border-top: 1px dashed var(--simko-border);
}

.success-total.is-final dt {
  color: var(--simko-ink);
  font-size: 1rem;
  font-weight: 800;
}

.success-total.is-final dd {
  color: var(--simko-brand);
  font-size: 1.125rem;
  font-weight: 800;
}

/* ------------------------------------------------------------------
 * Addresses and contact (.success-address, .success-line)
 * ------------------------------------------------------------------ */

.success-address {
  margin: 0;
  color: var(--simko-ink);
  font-size: 0.875rem;
  line-height: 1.7;
}

.success-line {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
  margin: 0.85rem 0 0;
  padding-top: 0.75rem;
  border-top: 1px solid var(--simko-border);
  font-size: 0.8125rem;
}

.success-line span {
  color: var(--simko-ink-muted);
}

.success-line strong {
  color: var(--simko-ink);
  text-align: right;
}

.success-contact {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 0.4rem;
  color: var(--simko-ink);
  font-size: 0.875rem;
  overflow-wrap: anywhere;
}

.success-contact i {
  flex: none;
  width: 1rem;
  color: var(--simko-brand);
  font-size: 0.8125rem;
  text-align: center;
}

.success-help {
  margin: 0.85rem 0 0;
  padding-top: 0.75rem;
  border-top: 1px solid var(--simko-border);
  color: var(--simko-ink-muted);
  font-size: 0.8125rem;
}

.success-help a {
  color: var(--simko-brand);
  font-weight: 600;
}

/* ------------------------------------------------------------------
 * A wider hero from md, two columns from lg
 * ------------------------------------------------------------------ */

@media (min-width: 768px) {
  .success-hero {
    padding: 2.5rem 2rem 2rem;
  }

  .success-title {
    font-size: 1.75rem;
  }

  .success-card {
    padding: 1.35rem 1.35rem 1.5rem;
  }

  /* The bank details and the reference sit side by side as soon as there is
     room, because they are used together. */
  .success-pay {
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: start;
  }
}

@media (min-width: 992px) {
  .success-layout {
    grid-template-columns: minmax(0, 1fr) 20.5rem;
    align-items: start;
  }
}

/* ------------------------------------------------------------------
 * Success page: arrival
 *
 * Same one-shot arrival the cart and the checkout use, gated on html.simko-js
 * and cancelled under prefers-reduced-motion.
 * ------------------------------------------------------------------ */

.simko-js .simko-arrive.success-hero,
.simko-js .simko-arrive.success-card,
.simko-js .simko-arrive.success-side {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 420ms var(--simko-ease), transform 420ms var(--simko-ease);
}

.simko-js .simko-arrive.success-card,
.simko-js .simko-arrive.success-side {
  transition-delay: calc(120ms + var(--card-index, 0) * 70ms);
}

.simko-js .simko-arrive-in.success-hero,
.simko-js .simko-arrive-in.success-card,
.simko-js .simko-arrive-in.success-side {
  opacity: 1;
  transform: none;
}

/* The tick lands a beat after the card it sits in, which is the one flourish on
   the page and the only thing on it worth drawing an eye to. */
.simko-js .simko-arrive.success-hero .success-mark {
  transform: scale(0.8);
  transition: transform 460ms var(--simko-ease) 200ms;
}

.simko-js .simko-arrive-in.success-hero .success-mark {
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .simko-js .simko-arrive.success-hero,
  .simko-js .simko-arrive.success-card,
  .simko-js .simko-arrive.success-side {
    opacity: 1;
    transform: none;
    transition: none;
    transition-delay: 0s;
  }

  .simko-js .simko-arrive.success-hero .success-mark,
  .simko-js .simko-arrive-in.success-hero .success-mark {
    transform: none;
    transition: none;
  }

  .success-btn {
    transition: none;
  }
}

/* ------------------------------------------------------------------
 * Account: login and register (.auth-page)
 *
 * Both pages are the same shell: the form in a card that is the page, and a
 * panel beside it pointing at the other one. The panel is second in the
 * document, so below lg -- where the two stack -- the form comes first, which is
 * the order they are wanted in.
 *
 * The fields themselves are the checkout's (.checkout-grid, .checkout-field,
 * .checkout-input, .checkout-switch, .checkout-submit), not a second set: a
 * shopper meets the register form at checkout too, and two forms that ask for
 * the same things should not look like two stores.
 * ------------------------------------------------------------------ */

.auth-page {
  padding-bottom: 2.5rem;
}

.auth-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1rem;
  align-items: start;
}

/* The panel only earns a column of its own once there is room for the form to
   keep a comfortable measure beside it. Below that it sits under the form at
   full width, which is also where it stops competing with the fields.

   xl rather than lg because these pages are laid out with core's account link
   list in #column-right, which already takes a quarter of the row: at lg that
   leaves the form about 350px, and the field grid goes two-across from md. */
@media (min-width: 1200px) {
  .auth-layout {
    grid-template-columns: minmax(0, 1fr) 300px;
    gap: 1.5rem;
  }
}

.auth-card {
  min-width: 0;
  padding: 1.35rem;
  background-color: #fff;
  border: 1px solid var(--simko-border);
  border-radius: 14px;
}

/* The login page. Two fields do not want the whole content width, and the field
   grid goes two-across from md -- which put the password beside the e-mail
   address rather than after it, so the form read as a row instead of as a
   sequence. Capped and single-column: a sign-in form is a short vertical list
   and it should look like one.

   Centred in the row: this page carries no account list in #column-right, so a
   cap that only limits the width leaves the pair pinned to the left edge of a
   wide, otherwise empty row. */
.auth-page-single .auth-layout {
  max-width: 50rem;
  margin-inline: auto;
}

.auth-page-single .auth-card,
.auth-page-single .auth-aside {
  max-width: 30rem;
}

/* Below xl the two are stacked in one column wider than their cap, so they need
   centring of their own. Above it they are grid items that should fill their
   column, and an auto inline margin would make them shrink to fit instead. */
@media (max-width: 1199.98px) {
  .auth-page-single .auth-card,
  .auth-page-single .auth-aside {
    margin-inline: auto;
  }
}

.auth-page-single .checkout-grid {
  grid-template-columns: minmax(0, 1fr);
}

/* Full width inside a capped card, rather than the auto width the checkout's
   submit takes from md under a two-column grid. */
.auth-page-single .checkout-submit {
  width: 100%;
}

/* The button is the next thing after the last field, not a part of it. The
   checkout's own submit gets this spacing from the consents block above it,
   which neither of these forms has in the same place. */
.auth-page .checkout-submit {
  margin-top: 1.35rem;
}

@media (min-width: 768px) {
  .auth-card {
    padding: 1.85rem;
  }
}

.auth-head {
  margin-bottom: 1.35rem;
}

.auth-title {
  margin: 0 0 0.35rem;
  font-size: 1.5rem;
  font-weight: 800;
  line-height: 1.2;
  letter-spacing: -0.01em;
  color: var(--simko-ink);
}

@media (min-width: 768px) {
  .auth-title {
    font-size: 1.75rem;
  }
}

.auth-intro {
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--simko-ink-muted);
}

/* A session message -- a password just reset, or a stale customer token. About
   the page rather than about a submission, so it sits above the form; what the
   form itself is told lands in .checkout-form-note under the button.

   Core printed both as dismissible Bootstrap alerts in #alert at the very top of
   the document, above the announcement bar and the header. */
.auth-alert {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  margin-bottom: 1.15rem;
  padding: 0.75rem 0.9rem;
  border-radius: 12px;
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.45;
}

.auth-alert i {
  margin-top: 0.15rem;
}

.auth-alert-error {
  color: var(--simko-brand);
  background-color: var(--simko-tint);
}

.auth-alert-success {
  color: #1f7a3d;
  background-color: rgba(31, 122, 61, 0.09);
}

/* The label and the way out of the field share a line. Baseline rather than
   centre, so the small link sits on the label's baseline instead of floating in
   the middle of its box. */
.auth-label-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
}

.auth-forgot {
  flex: none;
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--simko-brand);
  text-decoration: none;
}

.auth-forgot:hover,
.auth-forgot:focus-visible {
  color: var(--simko-brand-dark);
}

/* ------------------------------------------------------------------
 * Password field: the reveal button and the live checklist
 * ------------------------------------------------------------------ */

.auth-control {
  position: relative;
}

/* Room for the button, so a long password does not run under it. */
.auth-control .checkout-input {
  padding-right: 3rem;
}

.auth-reveal {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  padding: 0;
  border: 0;
  background: none;
  color: var(--simko-ink-muted);
  cursor: pointer;
  transition: color var(--simko-speed) var(--simko-ease);
}

.auth-reveal:hover,
.auth-reveal:focus-visible {
  color: var(--simko-brand);
}

.auth-reveal:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: -2px;
  border-radius: var(--simko-radius);
}

.auth-rules-title {
  margin: 0.6rem 0 0.35rem;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--simko-ink-muted);
}

.auth-rules {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Unmet is grey rather than red: nothing has gone wrong yet, the shopper is
   still typing. Only the server's answer is allowed to be an error. */
.auth-rule {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.2rem 0.6rem;
  border: 1px solid var(--simko-border);
  border-radius: 999px;
  background-color: #fff;
  font-size: 0.6875rem;
  font-weight: 600;
  line-height: 1.6;
  color: var(--simko-ink-muted);
  transition: color var(--simko-speed) var(--simko-ease), border-color var(--simko-speed) var(--simko-ease), background-color var(--simko-speed) var(--simko-ease);
}

.auth-rule i {
  font-size: 0.5rem;
}

.auth-rule.is-met {
  color: #1f7a3d;
  border-color: rgba(31, 122, 61, 0.35);
  background-color: rgba(31, 122, 61, 0.08);
}

.auth-rule.is-met i {
  font-size: 0.625rem;
}

.auth-switch-note {
  display: block;
  color: var(--simko-ink-muted);
}

/* Fields a captcha extension prints inside the form, which the child theme
   cannot put its own class on. Same treatment the checkout gives them. */
.auth-page .form-control,
.auth-page .form-select {
  min-height: var(--simko-control-h);
  border-color: var(--simko-border);
  border-radius: var(--simko-radius);
  font-size: 0.9375rem;
}

.auth-page .form-control:focus,
.auth-page .form-select:focus {
  border-color: var(--simko-brand);
  box-shadow: 0 0 0 3px var(--simko-tint);
}

/* ------------------------------------------------------------------
 * The panel beside the form (.auth-aside)
 *
 * Core made the same offer as a bordered box of equal weight to the login form,
 * carrying one paragraph of prose. Tinted rather than bordered, so it reads as
 * an aside to the card and not as a second form; three lines rather than a
 * paragraph, because a fourth stops being read.
 * ------------------------------------------------------------------ */

.auth-aside {
  min-width: 0;
  padding: 1.35rem;
  border: 1px solid rgba(218, 34, 41, 0.16);
  border-radius: 14px;
  background-color: var(--simko-tint);
}

@media (min-width: 1200px) {
  .auth-aside {
    position: sticky;
    top: 1.25rem;
  }
}

.auth-aside-title {
  margin: 0 0 0.3rem;
  font-size: 1.0625rem;
  font-weight: 800;
  color: var(--simko-ink);
}

.auth-aside-intro {
  margin: 0 0 1.1rem;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--simko-ink-muted);
}

.auth-benefits {
  display: grid;
  gap: 0.6rem;
  margin: 0 0 1.25rem;
  padding: 0;
  list-style: none;
}

.auth-benefit {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--simko-ink);
}

.auth-benefit i {
  flex: none;
  margin-top: 0.2rem;
  font-size: 0.75rem;
  color: var(--simko-brand);
}

/* The way to the other page. Outlined rather than filled: the filled button on
   the page belongs to the form, and two solid brand buttons would leave the
   shopper picking between them. */
.auth-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  width: 100%;
  min-height: var(--simko-touch);
  padding: 0 1rem;
  border: 1px solid var(--simko-brand);
  border-radius: var(--simko-radius);
  background-color: #fff;
  color: var(--simko-brand);
  font-size: 0.875rem;
  font-weight: 700;
  text-decoration: none;
  transition: background-color var(--simko-speed) var(--simko-ease), color var(--simko-speed) var(--simko-ease);
}

.auth-btn:hover,
.auth-btn:focus-visible {
  background-color: var(--simko-brand);
  color: #fff;
}

.auth-btn:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

/* ------------------------------------------------------------------
 * Account: arrival
 *
 * Same one-shot arrival the cart, the checkout and the success page use, gated
 * on html.simko-js and cancelled under prefers-reduced-motion.
 * ------------------------------------------------------------------ */

.simko-js .simko-arrive.auth-card,
.simko-js .simko-arrive.auth-aside {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 420ms var(--simko-ease), transform 420ms var(--simko-ease);
  transition-delay: calc(var(--card-index, 0) * 90ms);
}

.simko-js .simko-arrive-in.auth-card,
.simko-js .simko-arrive-in.auth-aside {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .simko-js .simko-arrive.auth-card,
  .simko-js .simko-arrive.auth-aside {
    opacity: 1;
    transform: none;
    transition: none;
    transition-delay: 0s;
  }

  .auth-rule,
  .auth-reveal,
  .auth-btn {
    transition: none;
  }
}

/* ------------------------------------------------------------------
 * Information pages (.info-page)
 *
 * The admin-authored pages -- terms, privacy, delivery, about. The markup
 * inside .info-prose is whatever the editor produced, so it arrives without
 * classes and every rule here is a bare element selector scoped to that one
 * wrapper rather than anything global.
 *
 * The card is capped at 46rem: these pages are read top to bottom, and the
 * content column on a desktop is nearly three times a comfortable measure.
 * ------------------------------------------------------------------ */

.info-page {
  padding-bottom: 3rem;
}

.info-head {
  margin-bottom: 1.25rem;
}

.info-title {
  margin: 0;
  font-size: 1.75rem;
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.015em;
  color: var(--simko-ink);
}

/* The column these pages are read in. The content row is nearly three times a
   comfortable measure on a desktop, and none of these pages has a sidebar to
   fill the rest of it -- so the column is capped and centred rather than left
   hanging against the left edge of an empty row. */
.info-layout {
  max-width: 46rem;
  margin-inline: auto;
}

.info-intro {
  margin: 0.5rem 0 0;
  font-size: 1rem;
  line-height: 1.6;
  color: var(--simko-ink-muted);
}

.info-body {
  padding: 1.35rem;
  background-color: #fff;
  border: 1px solid var(--simko-border);
  border-radius: 14px;
}

.info-body + .info-body,
.info-body + .contact-branches,
.contact-branches + .info-body {
  margin-top: 1rem;
}

/* Names a block inside a card -- the store's details, the enquiry form, each
   half of the GDPR request. Below the H1 in weight, and never the page's own
   title. */
.info-subtitle {
  margin: 0 0 1rem;
  font-size: 1.0625rem;
  font-weight: 800;
  line-height: 1.25;
  color: var(--simko-ink);
}

.info-subtitle-next {
  margin-top: 1.75rem;
}

@media (min-width: 768px) {
  .info-title {
    font-size: 2.125rem;
  }

  .info-body {
    padding: 1.85rem;
  }
}

.info-prose {
  font-size: 1rem;
  line-height: 1.7;
  color: var(--simko-ink);
}

/* The editor's first and last blocks carry their own margins, which would show
   as uneven padding at the top and bottom of the card. */
.info-prose > :first-child {
  margin-top: 0;
}

.info-prose > :last-child {
  margin-bottom: 0;
}

.info-prose p {
  margin: 0 0 1rem;
}

.info-prose h2 {
  margin: 2rem 0 0.65rem;
  font-size: 1.25rem;
  font-weight: 800;
  line-height: 1.25;
  letter-spacing: -0.01em;
  color: var(--simko-ink);
}

.info-prose h3,
.info-prose h4 {
  margin: 1.5rem 0 0.5rem;
  font-size: 1.0625rem;
  font-weight: 700;
  line-height: 1.3;
  color: var(--simko-ink);
}

.info-prose ul,
.info-prose ol {
  margin: 0 0 1rem;
  padding-left: 1.25rem;
}

.info-prose li {
  margin-bottom: 0.4rem;
}

.info-prose li:last-child {
  margin-bottom: 0;
}

.info-prose a {
  color: var(--simko-brand);
  text-decoration: underline;
  text-underline-offset: 0.15em;
  transition: color var(--simko-speed) var(--simko-ease);
}

.info-prose a:hover,
.info-prose a:focus-visible {
  color: var(--simko-brand-dark);
}

.info-prose strong,
.info-prose b {
  font-weight: 700;
}

.info-prose hr {
  height: 0;
  margin: 1.75rem 0;
  border: 0;
  border-top: 1px solid var(--simko-border);
  opacity: 1;
}

.info-prose blockquote {
  margin: 0 0 1rem;
  padding: 0.15rem 0 0.15rem 1rem;
  border-left: 3px solid var(--simko-brand);
  color: var(--simko-ink-muted);
}

.info-prose img {
  max-width: 100%;
  height: auto;
  border-radius: 10px;
}

/* A pasted table is the one thing in here that can be wider than the card, and
   there is no wrapper to scroll it in -- so the table is the scroller. */
.info-prose table {
  display: block;
  width: 100%;
  margin: 0 0 1rem;
  overflow-x: auto;
  border-collapse: collapse;
  font-size: 0.9375rem;
}

.info-prose th,
.info-prose td {
  padding: 0.6rem 0.75rem;
  text-align: left;
  vertical-align: top;
  border: 1px solid var(--simko-border);
}

.info-prose th {
  font-weight: 700;
  background-color: #fafafa;
}

/* ------------------------------------------------------------------
 * Information pages: arrival
 *
 * Same one-shot arrival the cart, the checkout, the success page and the
 * account pages use, gated on html.simko-js and cancelled under
 * prefers-reduced-motion.
 * ------------------------------------------------------------------ */

.simko-js .simko-arrive.info-head,
.simko-js .simko-arrive.info-body,
.simko-js .simko-arrive.contact-branches,
.simko-js .simko-arrive.sitemap-card {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 420ms var(--simko-ease), transform 420ms var(--simko-ease);
  transition-delay: calc(var(--card-index, 0) * 90ms);
}

.simko-js .simko-arrive-in.info-head,
.simko-js .simko-arrive-in.info-body,
.simko-js .simko-arrive-in.contact-branches,
.simko-js .simko-arrive-in.sitemap-card {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .simko-js .simko-arrive.info-head,
  .simko-js .simko-arrive.info-body,
  .simko-js .simko-arrive.contact-branches,
  .simko-js .simko-arrive.sitemap-card {
    opacity: 1;
    transform: none;
    transition: none;
    transition-delay: 0s;
  }

  .info-prose a,
  .contact-map,
  .sitemap-link,
  .gdpr-cancel {
    transition: none;
  }
}

/* ------------------------------------------------------------------
 * Contact page (.contact-page)
 *
 * Two things, in the order they are wanted: where the store is, then the way to
 * reach it. Core printed the details as four columns of <strong> and <br/>
 * pairs, which collapse to four unlabelled paragraphs on a phone; they are a
 * labelled list here, one row per fact, and the row is the same shape at every
 * width.
 * ------------------------------------------------------------------ */

.contact-store {
  display: grid;
  gap: 1rem;
}

.contact-store-figure {
  min-width: 0;
}

.contact-store-image {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 12px;
}

.contact-store-name {
  margin: 0 0 0.85rem;
  font-size: 1rem;
  font-weight: 700;
  color: var(--simko-ink);
}

.contact-facts {
  display: grid;
  gap: 0.9rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.contact-fact {
  display: flex;
  gap: 0.75rem;
  align-items: flex-start;
}

/* Fixed width so every label starts on the same line, whatever the icon is. */
.contact-fact > i {
  flex: 0 0 1.25rem;
  margin-top: 0.2rem;
  font-size: 0.875rem;
  text-align: center;
  color: var(--simko-brand);
}

.contact-fact-body {
  min-width: 0;
}

.contact-fact-label {
  display: block;
  margin-bottom: 0.15rem;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--simko-ink-muted);
}

/* <address> is italic by default, and the value is an address on one row and a
   phone number on the next -- they should not be set in two different faces. */
.contact-fact-value {
  margin: 0;
  font-size: 0.9375rem;
  font-style: normal;
  line-height: 1.6;
  color: var(--simko-ink);
}

.contact-fact-value a {
  color: var(--simko-ink);
  text-decoration: none;
}

.contact-fact-value a:hover,
.contact-fact-value a:focus-visible {
  color: var(--simko-brand);
}

.contact-map {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.55rem;
  font-size: 0.8125rem;
  font-weight: 700;
  color: var(--simko-brand);
  text-decoration: none;
  transition: color var(--simko-speed) var(--simko-ease);
}

.contact-map:hover,
.contact-map:focus-visible {
  color: var(--simko-brand-dark);
}

.contact-branches {
  margin-top: 1rem;
}

.contact-branch-list {
  display: grid;
  gap: 0.75rem;
}

.contact-branch {
  padding: 1.1rem;
  background-color: #fff;
  border: 1px solid var(--simko-border);
  border-radius: 14px;
}

.contact-branch-image {
  display: block;
  width: 100%;
  height: auto;
  margin-bottom: 0.75rem;
  border-radius: 10px;
}

.contact-branch-name {
  margin: 0 0 0.35rem;
  font-size: 0.9375rem;
  font-weight: 700;
  color: var(--simko-ink);
}

.contact-branch-address {
  margin: 0 0 0.5rem;
  font-size: 0.875rem;
  font-style: normal;
  line-height: 1.6;
  color: var(--simko-ink-muted);
}

.contact-branch-line {
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
  margin: 0 0 0.3rem;
  font-size: 0.875rem;
  color: var(--simko-ink);
}

.contact-branch-line i {
  font-size: 0.75rem;
  color: var(--simko-brand);
}

.contact-branch-line a {
  color: inherit;
  text-decoration: none;
}

.contact-branch-line a:hover,
.contact-branch-line a:focus-visible {
  color: var(--simko-brand);
}

.contact-branch-note {
  margin: 0.5rem 0 0;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--simko-ink-muted);
}

/* The send button sits straight after the last field, so it needs the same
   gap the form puts between its own blocks. */
#form-contact .checkout-submit {
  margin-top: 1.35rem;
}

/* The picture beside the details rather than above them, once there is room for
   both to keep a usable width. */
@media (min-width: 576px) {
  .contact-branch-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 768px) {
  .contact-store:has(.contact-store-figure) {
    grid-template-columns: 180px minmax(0, 1fr);
    gap: 1.25rem;
    align-items: start;
  }
}

/* ------------------------------------------------------------------
 * Site map (.sitemap-page)
 *
 * Core's two columns of nested browser-default lists, rebuilt as cards. The
 * grid is the page's only layout -- each card is a list, and the tree's levels
 * are told apart by indent, size and weight rather than by bullet.
 * ------------------------------------------------------------------ */

.sitemap-grid {
  display: grid;
  gap: 1rem;
  align-items: start;
}

.sitemap-card {
  min-width: 0;
  padding: 1.35rem;
  background-color: #fff;
  border: 1px solid var(--simko-border);
  border-radius: 14px;
}

.sitemap-card-title {
  margin: 0 0 0.85rem;
  font-size: 0.75rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--simko-ink-muted);
}

.sitemap-card-title-next {
  margin-top: 1.5rem;
}

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

/* The indent is on the nested list, not on the item, so a link's hit area still
   starts at the card's edge. */
.sitemap-tree-2 {
  margin-top: 0.3rem;
  padding-left: 0.85rem;
  border-left: 1px solid var(--simko-border);
}

.sitemap-tree-3 {
  margin-top: 0.25rem;
  padding-left: 0.85rem;
  border-left: 1px solid var(--simko-border);
}

.sitemap-branch {
  margin-bottom: 0.3rem;
}

.sitemap-branch:last-child {
  margin-bottom: 0;
}

.sitemap-link {
  display: inline-block;
  padding: 0.15rem 0;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--simko-ink-muted);
  text-decoration: none;
  transition: color var(--simko-speed) var(--simko-ease);
}

/* A top-level entry: a category the store actually sells from, or a page that
   is not filed under another one. */
.sitemap-link-1 {
  font-weight: 700;
  color: var(--simko-ink);
}

.sitemap-link:hover,
.sitemap-link:focus-visible {
  color: var(--simko-brand);
}

@media (min-width: 576px) {
  .sitemap-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 992px) {
  .sitemap-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* ------------------------------------------------------------------
 * GDPR request (.gdpr-page)
 *
 * One form, two decisions: whose data, and what to do with it. The warning is
 * attached to the destructive one and only shown when it is chosen.
 * ------------------------------------------------------------------ */

.gdpr-hint {
  margin: -0.35rem 0 1rem;
}

.gdpr-warning {
  margin-top: 1rem;
  padding: 1rem 1.1rem;
  background-color: var(--simko-tint);
  border: 1px solid var(--simko-brand);
  border-radius: 12px;
}

.gdpr-warning[hidden] {
  display: none;
}

.gdpr-warning-title {
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
  margin: 0 0 0.6rem;
  font-size: 0.9375rem;
  font-weight: 700;
  color: var(--simko-brand-dark);
}

.gdpr-warning-list {
  margin: 0;
  padding-left: 1.1rem;
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--simko-ink);
}

.gdpr-warning-list li + li {
  margin-top: 0.35rem;
}

/* The way out sits beside the way on, not above it: cancelling is the rarer
   choice and should not be the first thing under the last field. */
.gdpr-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.85rem;
  margin-top: 1.35rem;
}

.gdpr-actions .checkout-submit {
  margin-top: 0;
}

.gdpr-cancel {
  min-height: var(--simko-touch);
  display: inline-flex;
  align-items: center;
  font-size: 0.875rem;
  font-weight: 700;
  color: var(--simko-ink-muted);
  text-decoration: none;
  transition: color var(--simko-speed) var(--simko-ease);
}

.gdpr-cancel:hover,
.gdpr-cancel:focus-visible {
  color: var(--simko-brand);
}

/* ------------------------------------------------------------------
 * Account area (.account-page)
 *
 * Core's account area is twenty-odd pages that share nothing: each is an H1 over
 * a bordered table or a two-column Bootstrap form, and the only way from one to
 * the next is back to the account index and down a list of thirteen links. Read
 * on a phone, every one of those tables scrolls sideways, and every form's
 * answer arrives at the top of the document, a screen above the button pressed.
 *
 * So the area gets a shell: a sidebar of sections that is the same on every
 * page, and one page body beside it. Below lg the sidebar becomes a scrolling
 * row of chips above the content -- one markup path, two layouts.
 *
 * Nothing new is invented for the inside of a page. The panels are the cart
 * summary's border, radius and ground; the forms are the checkout's .checkout-*
 * grid and controls; the buttons are the checkout's submit and the cart's quiet
 * remove. Red is spent on the one action a page is for, and on saying where you
 * are.
 * ------------------------------------------------------------------ */

.account-page {
  padding-bottom: 3rem;
}

.account-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.25rem;
  align-items: start;
}

@media (min-width: 992px) {
  .account-layout {
    grid-template-columns: 232px minmax(0, 1fr);
    gap: 2rem;
  }

  /* The sidebar follows down a long order page rather than scrolling away with
     it: it is the only way out of the page you are on. */
  .account-side {
    position: sticky;
    top: 1rem;
  }
}

.account-main {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

/* ------------------------------------------------------------------
 * The sidebar (.account-nav)
 *
 * Below lg it is one horizontal strip: the groups still exist in the markup --
 * they are what the overview's cards are built from -- but their headings are
 * hidden and the links run in a single scrolling row. accountArea() scrolls the
 * current chip into view, since it is the one that says where you are.
 * ------------------------------------------------------------------ */

.account-nav {
  display: flex;
  gap: 0.5rem;
  margin: 0;
  padding: 0 0 0.25rem;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}

.account-nav::-webkit-scrollbar {
  display: none;
}

.account-nav-group {
  display: contents;
}

.account-nav-title {
  display: none;
}

.account-nav-list {
  display: flex;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.account-nav-item {
  flex: 0 0 auto;
}

.account-nav-link,
.account-nav-out {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: var(--simko-touch);
  padding: 0 0.9rem;
  border: 1px solid var(--simko-border);
  border-radius: 999px;
  background-color: #fff;
  color: var(--simko-ink);
  font-size: 0.875rem;
  font-weight: 600;
  white-space: nowrap;
  text-decoration: none;
  transition:
    color var(--simko-speed) var(--simko-ease),
    border-color var(--simko-speed) var(--simko-ease),
    background-color var(--simko-speed) var(--simko-ease);
}

.account-nav-link i,
.account-nav-out i {
  font-size: 0.8125rem;
  color: var(--simko-ink-muted);
  transition: color var(--simko-speed) var(--simko-ease);
}

.account-nav-link:hover,
.account-nav-link:focus-visible,
.account-nav-out:hover,
.account-nav-out:focus-visible {
  color: var(--simko-brand);
  border-color: var(--simko-brand);
}

.account-nav-link:hover i,
.account-nav-link:focus-visible i,
.account-nav-out:hover i,
.account-nav-out:focus-visible i {
  color: var(--simko-brand);
}

.account-nav-link:focus-visible,
.account-nav-out:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

/* Where you are, said three ways -- the fill, the colour and the weight -- so it
   is not carried by hue alone. */
.account-nav-link.is-current {
  color: var(--simko-brand);
  background-color: var(--simko-tint);
  border-color: var(--simko-brand);
  font-weight: 700;
}

.account-nav-link.is-current i {
  color: var(--simko-brand);
}

.account-nav-out {
  flex: 0 0 auto;
  color: var(--simko-ink-muted);
}

@media (min-width: 992px) {
  .account-nav {
    display: block;
    padding: 0;
    overflow: visible;
  }

  .account-nav-group {
    display: block;
  }

  .account-nav-group + .account-nav-group {
    margin-top: 1.35rem;
  }

  .account-nav-title {
    display: block;
    margin: 0 0 0.5rem;
    padding: 0 0.65rem;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--simko-ink-muted);
  }

  .account-nav-list {
    display: block;
  }

  .account-nav-link,
  .account-nav-out {
    display: flex;
    width: 100%;
    min-height: 40px;
    padding: 0 0.65rem;
    border: 0;
    border-radius: 10px;
    background-color: transparent;
    white-space: normal;
  }

  .account-nav-link i,
  .account-nav-out i {
    /* A fixed box, so the labels line up whatever width their icons are. */
    width: 1.1rem;
    text-align: center;
    flex: 0 0 auto;
  }

  .account-nav-link:hover,
  .account-nav-link:focus-visible,
  .account-nav-out:hover,
  .account-nav-out:focus-visible {
    background-color: var(--simko-tint);
  }

  .account-nav-link.is-current {
    background-color: var(--simko-tint);
  }

  .account-nav-out {
    margin-top: 1.35rem;
    border-top: 1px solid var(--simko-border);
    border-radius: 0 0 10px 10px;
    padding-top: 0.75rem;
    min-height: 52px;
  }
}

/* ------------------------------------------------------------------
 * The page's own header (.account-head)
 * ------------------------------------------------------------------ */

.account-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.85rem;
  /* The rule underneath is deliberate here, and given room to breathe: the
     heading and the line under it are the page's own divider, not the site
     header's. */
  padding-bottom: 1.1rem;
  margin-bottom: 0.75rem;
  border-bottom: 1px solid var(--simko-border);
}

.account-head-text {
  min-width: 0;
}

/* A page with an action beside its heading wraps the words in .account-head-text
   and the two sit side by side. A page without one leaves the heading and its
   line as direct children, and they take a line each rather than becoming two
   flex items on one row. */
.account-head > .account-title,
.account-head > .account-intro {
  flex: 1 1 100%;
}

.account-title {
  margin: 0;
  font-size: 1.625rem;
  font-weight: 800;
  line-height: 1.15;
  letter-spacing: -0.015em;
  color: var(--simko-ink);
}

.account-intro {
  margin: 0.35rem 0 0;
  max-width: 62ch;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--simko-ink-muted);
}

/* Carried over from a redirect -- an address saved, a password changed. */
.account-alert {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  padding: 0.8rem 1rem;
  border-radius: 12px;
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.45;
}

.account-alert i {
  margin-top: 0.15rem;
}

.account-alert-success {
  background-color: #eef8f1;
  color: #1f7a3d;
}

.account-alert-error {
  background-color: var(--simko-tint);
  color: var(--simko-brand);
}

/* ------------------------------------------------------------------
 * Buttons (.account-btn)
 *
 * Three weights: the one thing the page is for, the way back, and the
 * destructive one -- which stays quiet until it is aimed at, the same way the
 * cart's remove does.
 * ------------------------------------------------------------------ */

.account-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: var(--simko-touch);
  padding: 0 1.15rem;
  border: 1px solid transparent;
  border-radius: var(--simko-radius);
  font-size: 0.875rem;
  font-weight: 700;
  text-decoration: none;
  white-space: nowrap;
  transition:
    color var(--simko-speed) var(--simko-ease),
    border-color var(--simko-speed) var(--simko-ease),
    background-color var(--simko-speed) var(--simko-ease);
}

.account-btn i {
  font-size: 0.8125rem;
}

.account-btn:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

.account-btn-solid {
  background-color: var(--simko-brand);
  border-color: var(--simko-brand);
  color: #fff;
}

.account-btn-solid:hover,
.account-btn-solid:focus-visible {
  background-color: var(--simko-brand-dark);
  border-color: var(--simko-brand-dark);
  color: #fff;
}

.account-btn-ghost {
  background-color: #fff;
  border-color: var(--simko-border);
  color: var(--simko-ink);
}

.account-btn-ghost:hover,
.account-btn-ghost:focus-visible {
  border-color: var(--simko-brand);
  color: var(--simko-brand);
}

.account-btn-quiet {
  background-color: transparent;
  border-color: transparent;
  color: var(--simko-ink-muted);
}

.account-btn-quiet:hover,
.account-btn-quiet:focus-visible {
  color: var(--simko-brand);
  background-color: var(--simko-tint);
}

.account-btn-sm {
  min-height: 38px;
  padding: 0 0.85rem;
  font-size: 0.8125rem;
}

.account-btn:disabled,
.account-btn.is-working {
  opacity: 0.6;
  cursor: progress;
}

.account-btn.is-done {
  color: #1f7a3d;
}

/* The two rows a page ends on: a form's pair, and a page's way back. */
.account-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-top: 1.35rem;
}

.account-submit {
  width: auto;
  min-width: 12rem;
}

@media (max-width: 575.98px) {
  .account-actions {
    flex-direction: column-reverse;
    align-items: stretch;
  }

  .account-submit {
    width: 100%;
    min-width: 0;
  }
}

.account-foot {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

/* A link inside a note the store wrote -- cart.add's success names the product
   and the cart -- takes the note's own colour rather than the brand red on red. */
.checkout-form-note a {
  color: inherit;
  text-decoration: underline;
}

.account-link {
  color: var(--simko-brand);
  font-weight: 600;
  text-decoration: none;
}

.account-link:hover,
.account-link:focus-visible {
  color: var(--simko-brand-dark);
}

/* ------------------------------------------------------------------
 * The overview's counts and cards
 * ------------------------------------------------------------------ */

.account-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 0.75rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.account-stat-link {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  height: 100%;
  padding: 0.9rem 1rem;
  border: 1px solid var(--simko-border);
  border-radius: 14px;
  background-color: #fff;
  text-decoration: none;
  transition:
    border-color var(--simko-speed) var(--simko-ease),
    transform var(--simko-speed) var(--simko-ease);
}

.account-stat-link:hover,
.account-stat-link:focus-visible {
  border-color: var(--simko-brand);
  transform: translateY(-2px);
}

.account-stat-link:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

@media (max-width: 575.98px) {
  .account-stats {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .account-stat-link {
    flex-direction: column;
    align-items: flex-start;
    gap: 0.5rem;
    padding: 0.75rem;
  }
}

.account-stat-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border-radius: 12px;
  background-color: var(--simko-tint);
  color: var(--simko-brand);
}

.account-stat-body {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.account-stat-value {
  font-size: 1.375rem;
  font-weight: 800;
  line-height: 1.1;
  color: var(--simko-ink);
}

.account-stat-text {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--simko-ink-muted);
}

.account-section-title {
  margin: 0 0 0.75rem;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--simko-ink-muted);
}

.account-cards {
  display: grid;
  /* auto-fill rather than auto-fit: a group with one card in it -- the newsletter
     -- keeps a card's width instead of stretching across the page. */
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 0.75rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.account-card-link {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  height: 100%;
  padding: 0.9rem 1rem;
  border: 1px solid var(--simko-border);
  border-radius: 14px;
  background-color: #fff;
  text-decoration: none;
  transition:
    border-color var(--simko-speed) var(--simko-ease),
    background-color var(--simko-speed) var(--simko-ease);
}

.account-card-link:hover,
.account-card-link:focus-visible {
  border-color: var(--simko-brand);
  background-color: #fffafa;
}

.account-card-link:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

.account-card-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  border-radius: 10px;
  background-color: #f6f6f6;
  color: var(--simko-ink-muted);
  transition:
    background-color var(--simko-speed) var(--simko-ease),
    color var(--simko-speed) var(--simko-ease);
}

.account-card-link:hover .account-card-icon,
.account-card-link:focus-visible .account-card-icon {
  background-color: var(--simko-tint);
  color: var(--simko-brand);
}

.account-card-body {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-width: 0;
  flex: 1 1 auto;
}

.account-card-name {
  font-size: 0.9375rem;
  font-weight: 700;
  color: var(--simko-ink);
}

.account-card-note {
  font-size: 0.8125rem;
  line-height: 1.4;
  color: var(--simko-ink-muted);
}

.account-card-go {
  flex: 0 0 auto;
  font-size: 0.75rem;
  color: var(--simko-border);
  transition: color var(--simko-speed) var(--simko-ease), transform var(--simko-speed) var(--simko-ease);
}

.account-card-link:hover .account-card-go,
.account-card-link:focus-visible .account-card-go {
  color: var(--simko-brand);
  transform: translateX(2px);
}

/* ------------------------------------------------------------------
 * Panels (.account-panel)
 *
 * The cart summary's surface: one border, one radius, white. .is-flush is for a
 * panel whose content draws its own padding -- a list of lines, a timeline --
 * and .account-panel-totals is the one panel on a page that is not white, so the
 * amount that was charged reads as the answer rather than another row.
 * ------------------------------------------------------------------ */

.account-panel {
  padding: 1.125rem 1.25rem 1.25rem;
  border: 1px solid var(--simko-border);
  border-radius: 14px;
  background-color: #fff;
}

.account-panel-flush {
  padding: 0;
  overflow: hidden;
}

.account-panel-narrow {
  max-width: 34rem;
}

.account-panel-totals {
  background-color: #fafafa;
}

.account-panel-title {
  margin: 0 0 0.875rem;
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--simko-ink-muted);
}

.account-panel-title-inset {
  margin: 0;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--simko-border);
}

.account-panel-foot {
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--simko-border);
}

/* A form panel holds the checkout's grid, which is capped so a postcode does
   not get a 900px box on a desktop. */
.account-panel-form .checkout-grid {
  max-width: 44rem;
}

@media (min-width: 768px) {
  .account-panel-form .checkout-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .account-panel-form .checkout-field.is-wide {
    grid-column: 1 / -1;
  }
}

.account-columns {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.25rem;
}

@media (min-width: 768px) {
  .account-columns {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* ------------------------------------------------------------------
 * Facts (.account-facts)
 *
 * Core printed read-only order details inside .form-control divs with fixed
 * min-heights -- a fact styled as an empty input, which looks like something you
 * can type in. A definition list says the same thing and reads as a fact.
 * ------------------------------------------------------------------ */

.account-facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 0.85rem 1.25rem;
  margin: 0;
}

.account-fact {
  min-width: 0;
}

.account-fact dt,
.account-facts dt {
  margin: 0 0 0.15rem;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--simko-ink-muted);
}

.account-fact dd,
.account-facts dd {
  margin: 0;
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--simko-ink);
  overflow-wrap: anywhere;
}

.account-fact-strong {
  font-size: 1.0625rem !important;
  font-weight: 800 !important;
}

.account-tile-body {
  margin: 0;
  font-size: 0.9375rem;
  line-height: 1.55;
  color: var(--simko-ink);
}

.account-quiet {
  margin: 0;
  font-size: 0.875rem;
  color: var(--simko-ink-muted);
}

.account-quiet-inset,
/* A flush panel draws no padding of its own, so a line standing in for the list
   it would have held has to draw its own. */
.account-panel-flush > .account-quiet {
  padding: 1.25rem;
}

/* ------------------------------------------------------------------
 * An order, a return, a subscription in a list (.account-order)
 *
 * Core rendered each as a row of a six-column table: '#14' first and a 30px eye
 * icon last, scrolling sideways on a phone so the total and the way in were off
 * screen behind the number. Each is one thing that happened, with a state.
 * ------------------------------------------------------------------ */

.account-orders {
  display: grid;
  gap: 0.75rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.account-order {
  display: grid;
  gap: 0.85rem;
  padding: 1rem 1.15rem;
  border: 1px solid var(--simko-border);
  border-radius: 14px;
  background-color: #fff;
  transition: border-color var(--simko-speed) var(--simko-ease);
}

.account-order:hover {
  border-color: var(--simko-brand);
}

.account-order-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}

.account-order-id {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.account-order-no {
  font-size: 1.0625rem;
  font-weight: 800;
  color: var(--simko-ink);
}

.account-order-date {
  font-size: 0.75rem;
  color: var(--simko-ink-muted);
}

.account-order-desc {
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.45;
  color: var(--simko-ink);
}

.account-order-facts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.85rem 1.75rem;
  margin: 0;
}

.account-order .account-btn {
  justify-self: start;
}

/* The state, which is the thing the shopper came to read. Neutral rather than
   coloured: a store's own status names are arbitrary, and guessing a colour for
   'Denied' from its position in a list would be a guess. */
.account-pill {
  display: inline-flex;
  align-items: center;
  padding: 0.3rem 0.7rem;
  border-radius: 999px;
  background-color: #f2f2f2;
  color: var(--simko-ink);
  font-size: 0.75rem;
  font-weight: 700;
  white-space: nowrap;
}

.account-pill-sm {
  padding: 0.2rem 0.55rem;
  font-size: 0.6875rem;
}

/* ------------------------------------------------------------------
 * Lines inside an order (.account-lines)
 * ------------------------------------------------------------------ */

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

.account-line {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0.6rem;
  padding: 1rem 1.25rem;
}

.account-line + .account-line {
  border-top: 1px solid var(--simko-border);
}

@media (min-width: 768px) {
  .account-line {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      'body figures'
      'actions figures';
    align-items: start;
    column-gap: 1.5rem;
  }

  .account-line-body {
    grid-area: body;
  }

  .account-line-figures {
    grid-area: figures;
  }

  .account-line-actions {
    grid-area: actions;
  }
}

.account-line-body {
  min-width: 0;
}

.account-line-name {
  display: block;
  font-size: 0.9375rem;
  font-weight: 700;
  line-height: 1.35;
  color: var(--simko-ink);
  text-decoration: none;
}

a.account-line-name:hover,
a.account-line-name:focus-visible {
  color: var(--simko-brand);
}

.account-line-meta {
  margin: 0.35rem 0 0;
  padding: 0;
  list-style: none;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--simko-ink-muted);
}

.account-line-error {
  display: block;
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--simko-brand);
}

.account-line-error:empty {
  display: none;
}

.account-line-figures {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.1rem;
}

@media (min-width: 768px) {
  .account-line-figures {
    align-items: flex-end;
    text-align: right;
  }
}

.account-line-qty {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--simko-ink-muted);
}

.account-line-total {
  font-size: 1rem;
  font-weight: 800;
  color: var(--simko-ink);
}

.account-line-unit {
  font-size: 0.75rem;
  color: var(--simko-ink-muted);
}

.account-line-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

/* ------------------------------------------------------------------
 * Totals (.account-totals) and a running balance (.account-total)
 * ------------------------------------------------------------------ */

.account-totals {
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.875rem;
}

.account-total-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.25rem 0;
  color: var(--simko-ink-muted);
}

.account-total-row.is-final {
  margin-top: 0.5rem;
  padding-top: 0.65rem;
  border-top: 1px solid var(--simko-border);
  font-size: 1.0625rem;
  font-weight: 800;
  color: var(--simko-ink);
}

/* The balance on the store-credit and reward pages. Core stated it as a
   sentence in the body copy ('Your Total is: RM0.00.'); it is the one number on
   the page. */
.account-total {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 1rem 1.25rem;
  border: 1px solid var(--simko-border);
  border-radius: 14px;
  background-color: #fafafa;
}

.account-total-text {
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--simko-ink-muted);
}

.account-total-value {
  font-size: 1.5rem;
  font-weight: 800;
  color: var(--simko-ink);
}

/* ------------------------------------------------------------------
 * Tiles: addresses, saved payment methods (.account-grid)
 * ------------------------------------------------------------------ */

.account-grid {
  display: grid;
  gap: 0.75rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.account-grid-address,
.account-grid-payment {
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}

.account-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  padding: 1rem 1.15rem;
  border: 1px solid var(--simko-border);
  border-radius: 14px;
  background-color: #fff;
}

.account-tile.is-default {
  border-color: var(--simko-brand);
}

.account-tile-raw {
  gap: 0;
}

.account-tile-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-top: auto;
  padding-top: 0.35rem;
  border-top: 1px solid var(--simko-border);
}

.account-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  align-self: flex-start;
  padding: 0.2rem 0.6rem;
  border-radius: 999px;
  background-color: var(--simko-tint);
  color: var(--simko-brand);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
}

.account-badge i {
  font-size: 0.625rem;
}

/* ------------------------------------------------------------------
 * The wish list's products (.account-product)
 *
 * Core put these in a six-column table with the picture in the first cell. They
 * are products, and the storefront already knows how to show one.
 * ------------------------------------------------------------------ */

.account-grid-product {
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
}

.account-product {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--simko-border);
  border-radius: 14px;
  background-color: #fff;
  overflow: hidden;
  transition: border-color var(--simko-speed) var(--simko-ease);
}

.account-product:hover {
  border-color: var(--simko-brand);
}

.account-product-thumb {
  display: block;
  aspect-ratio: 1 / 1;
  background-color: #f6f6f6;
}

.account-product-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.account-product-thumb-empty {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  color: var(--simko-border);
  font-size: 1.75rem;
}

.account-product-body {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  flex: 1 1 auto;
  padding: 0.85rem 0.9rem 0;
}

.account-product-name {
  /* Two lines, then clipped: product names in this catalogue run long, and a
     third line pushes the price out of the card. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-size: 0.875rem;
  font-weight: 700;
  line-height: 1.35;
  color: var(--simko-ink);
  text-decoration: none;
}

.account-product-name:hover,
.account-product-name:focus-visible {
  color: var(--simko-brand);
}

.account-product-stock {
  margin: 0;
  font-size: 0.75rem;
  color: var(--simko-ink-muted);
}

.account-product-price {
  margin: 0.15rem 0 0;
  font-size: 1rem;
  font-weight: 800;
  color: var(--simko-ink);
}

.account-product-now {
  color: var(--simko-brand);
}

.account-product-was {
  margin-left: 0.35rem;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--simko-ink-muted);
}

.account-product-actions {
  display: grid;
  gap: 0.35rem;
  padding: 0.85rem 0.9rem;
}

.account-product-actions .account-btn {
  width: 100%;
}

/* ------------------------------------------------------------------
 * Tables that stay tables (.account-table)
 *
 * Only for rows that really are comparable -- downloads, credit, points, the
 * orders a subscription has produced. Below md each row becomes one labelled
 * block, so nothing scrolls sideways; the labels come from the same column
 * headings, through data-label.
 * ------------------------------------------------------------------ */

.account-table {
  width: 100%;
  margin: 0;
  border-collapse: collapse;
  font-size: 0.875rem;
}

.account-table th {
  padding: 0.75rem 1.25rem;
  border-bottom: 1px solid var(--simko-border);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  text-align: left;
  color: var(--simko-ink-muted);
  white-space: nowrap;
}

.account-table td {
  padding: 0.75rem 1.25rem;
  color: var(--simko-ink);
  vertical-align: middle;
}

.account-table tbody tr + tr td {
  border-top: 1px solid var(--simko-border);
}

.account-table-name {
  font-weight: 600;
}

.account-table-figure {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  white-space: nowrap;
}

.account-table th.account-table-end,
.account-table td.account-table-end {
  text-align: right;
}

@media (max-width: 767.98px) {
  .account-table thead {
    /* Not display:none -- a screen reader still reads the headings off the
       cells, and clip keeps them associated. */
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }

  .account-table,
  .account-table tbody,
  .account-table tr,
  .account-table td {
    display: block;
    width: 100%;
  }

  .account-table tr {
    padding: 0.85rem 1.15rem;
  }

  .account-table tbody tr + tr {
    border-top: 1px solid var(--simko-border);
  }

  .account-table tbody tr + tr td {
    border-top: 0;
  }

  .account-table td {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.2rem 0;
    text-align: right;
  }

  .account-table td::before {
    content: attr(data-label);
    flex: 0 0 auto;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    text-align: left;
    color: var(--simko-ink-muted);
  }

  /* A cell with no label is the row's action: it gets the full width and its
     own line rather than a blank left column. */
  .account-table td:not([data-label]) {
    justify-content: stretch;
    padding-top: 0.6rem;
  }

  .account-table td:not([data-label]) .account-btn {
    width: 100%;
  }
}

/* ------------------------------------------------------------------
 * History (.account-timeline)
 *
 * Core drew an order's history as a three-column table whose headings never
 * printed. A history is a sequence: the status is the entry, the date is under
 * it, and the comment follows only when there is one.
 * ------------------------------------------------------------------ */

.account-timeline {
  margin: 0;
  padding: 1.25rem 1.25rem 0.5rem;
  list-style: none;
}

.account-step {
  position: relative;
  padding: 0 0 1.1rem 1.5rem;
}

/* The line between the dots, drawn by the entry above it so the last one does
   not trail off into nothing. */
.account-step:not(:last-child)::before {
  content: '';
  position: absolute;
  top: 1rem;
  bottom: 0.1rem;
  left: 0.3rem;
  width: 1px;
  background-color: var(--simko-border);
}

.account-step-dot {
  position: absolute;
  top: 0.35rem;
  left: 0;
  width: 0.65rem;
  height: 0.65rem;
  border: 2px solid var(--simko-border);
  border-radius: 50%;
  background-color: #fff;
}

/* Newest first, which is the order the controller returns them in, so the top
   entry is where the order has actually got to. */
.account-step.is-latest .account-step-dot {
  border-color: var(--simko-brand);
  background-color: var(--simko-brand);
}

.account-step-name {
  margin: 0;
  font-size: 0.875rem;
  font-weight: 700;
  color: var(--simko-ink);
}

.account-step-date {
  margin: 0.1rem 0 0;
  font-size: 0.75rem;
  color: var(--simko-ink-muted);
}

.account-step-note {
  margin: 0.35rem 0 0;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: var(--simko-ink-muted);
}

/* ------------------------------------------------------------------
 * Pagination (.account-pager)
 * ------------------------------------------------------------------ */

.account-pager {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}

.account-pager-inset {
  padding: 0 1.25rem 1.25rem;
}

.account-pager-links .pagination {
  gap: 0.35rem;
  margin: 0;
}

.account-pager-links .page-link {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: var(--simko-touch);
  min-height: var(--simko-touch);
  border: 1px solid var(--simko-border);
  border-radius: var(--simko-radius);
  color: var(--simko-ink);
  font-weight: 600;
}

.account-pager-links .page-link:hover {
  color: var(--simko-brand);
  background-color: var(--simko-tint);
  border-color: var(--simko-brand);
}

.account-pager-links .page-link:focus {
  box-shadow: 0 0 0 3px var(--simko-tint);
}

.account-pager-links .page-item.active .page-link {
  color: #fff;
  background-color: var(--simko-brand);
  border-color: var(--simko-brand);
}

.account-pager-count {
  margin: 0;
  font-size: 0.8125rem;
  color: var(--simko-ink-muted);
}

/* ------------------------------------------------------------------
 * Empty states (.account-empty)
 *
 * Core answered every empty list on every one of these pages with the same
 * 'There are no results.' -- true, and no use: it never says what would put
 * something there.
 * ------------------------------------------------------------------ */

.account-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  padding: 3rem 1.5rem;
  border: 1px dashed var(--simko-border);
  border-radius: 14px;
  background-color: #fff;
  text-align: center;
}

.account-empty i {
  font-size: 2rem;
  color: var(--simko-border);
}

.account-empty-text {
  margin: 0;
  max-width: 40ch;
  font-size: 0.875rem;
  line-height: 1.55;
  color: var(--simko-ink-muted);
}

/* ------------------------------------------------------------------
 * The switch rows (.account-switch)
 *
 * Newsletter, default address, and the two agreements. Core drew these as a
 * Bootstrap form-switch in a two-column row, with the label in a column of its
 * own -- so on a phone the toggle sat under its own label with nothing beside
 * it. One row, pressable anywhere along its length.
 * ------------------------------------------------------------------ */

.account-switch {
  margin-top: 1.35rem;
}

.account-switch-input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.account-switch-label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: var(--simko-touch);
  padding: 0.85rem 1rem;
  border: 1px solid var(--simko-border);
  border-radius: 12px;
  background-color: #fff;
  cursor: pointer;
  transition: border-color var(--simko-speed) var(--simko-ease);
}

.account-switch-label:hover {
  border-color: var(--simko-brand);
}

.account-switch-input:focus-visible + .account-switch-label {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

.account-switch-input:checked + .account-switch-label {
  border-color: var(--simko-brand);
  background-color: #fffafa;
}

.account-switch-text {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-width: 0;
}

.account-switch-name {
  font-size: 0.9375rem;
  font-weight: 700;
  color: var(--simko-ink);
}

.account-switch-note {
  font-size: 0.8125rem;
  line-height: 1.4;
  color: var(--simko-ink-muted);
}

.account-switch-track {
  position: relative;
  flex: 0 0 auto;
  width: 46px;
  height: 26px;
  border-radius: 999px;
  background-color: #dcdcdc;
  transition: background-color var(--simko-speed) var(--simko-ease);
}

.account-switch-knob {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background-color: #fff;
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
  transition: transform var(--simko-speed) var(--simko-ease);
}

.account-switch-input:checked + .account-switch-label .account-switch-track {
  background-color: var(--simko-brand);
}

.account-switch-input:checked + .account-switch-label .account-switch-knob {
  transform: translateX(20px);
}

/* ------------------------------------------------------------------
 * Odds and ends
 * ------------------------------------------------------------------ */

/* The two-factor code. Six characters, so the field is sized for six and the
   value is set apart from the words around it. */
.account-code {
  max-width: 14rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 1.125rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}

/* The resend on the two-factor page is a button that has to read as the quiet
   way out, the same as the login page's 'forgotten password' link. */
.auth-forgot-button {
  border: 0;
  background: none;
  padding: 0;
}

.account-affiliate-block[hidden] {
  display: none;
}

/* ------------------------------------------------------------------
 * Arrival
 *
 * The same pattern the cart uses: gated on html.simko-js, set at parse time, so
 * with no script -- and under reduced motion, where the rules below are
 * cancelled -- the page is simply there. The sidebar follows the page rather
 * than landing with it.
 * ------------------------------------------------------------------ */

.simko-js .simko-arrive.account-side,
.simko-js .simko-arrive.account-main {
  opacity: 0;
  transform: translateY(12px);
  transition:
    opacity 380ms var(--simko-ease),
    transform 380ms var(--simko-ease);
}

.simko-js .simko-arrive.account-side {
  transition-delay: 90ms;
}

.simko-js .simko-arrive-in.account-side,
.simko-js .simko-arrive-in.account-main {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .simko-js .simko-arrive.account-side,
  .simko-js .simko-arrive.account-main {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .account-stat-link:hover,
  .account-card-link:hover .account-card-go {
    transform: none;
  }
}

/* ------------------------------------------------------------------
 * Footer (.site-footer)
 *
 * Core's footer was four columns of Bootstrap link lists on the page's own
 * white, separated from the content above it by an <hr>. On a long category
 * page there was nothing to say the page had ended -- the links simply carried
 * on in the same colour as everything else.
 *
 * A dark band instead, so the page ends somewhere. Not a neutral black:
 * --simko-footer is --simko-ink's darkness warmed towards the brand's red,
 * which keeps the band in the palette rather than reading as the one place the
 * theme ran out of colour.
 *
 * The brand red stays for the icons and for a link under the pointer, but not
 * for resting link text -- #da2229 on #211b1b measures 3.5:1 and small text
 * needs 4.5:1. --simko-brand-light reaches 4.6:1, so that is the hover; the
 * resting #cfcfcf is 10.8:1 and the muted labels 5.2:1.
 *
 * The layout is one brand column beside the link columns.
 * ------------------------------------------------------------------ */

/* Core hangs the footer off the bottom of the page with position: absolute and
   bottom: -1px inside a position: absolute #container, then reserves room for
   it by padding the content column -- 730px below sm, 400px above it. Those
   numbers are a guess at the footer's height: a footer taller than the guess is
   drawn over the end of the page, a shorter one leaves a band of empty white
   above it. This one is neither height, and would not be after the next link is
   added to a column.

   A column that pushes the footer down needs no guess, so that is what
   #container becomes here. Its children are all full-width blocks already, so
   turning it into a flex column changes nothing else about the page. */
body {
  height: auto;
}

#container {
  position: static;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  margin-bottom: 0;
}

#container > main {
  flex: 1 0 auto;
}

#content,
#column-left,
#column-right {
  padding-bottom: 0;
}

.site-footer {
  position: static;
  margin-top: 32px;
  padding: 0;
  border: 0;
  background-color: var(--simko-footer);
  color: #cfcfcf;
}

/* Only a small gap above the band: most pages already pad their last section
   (the homepage's rail carries 64px of its own), and the change of ground is
   what separates the footer from the page. The margin is there for the pages
   that end flush. */
.site-footer .footer-top {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 2rem;
  padding: 2.5rem 0 1.75rem;
}

/* ------------------------------------------------------------------
 * The brand column
 * ------------------------------------------------------------------ */

.footer-brand {
  min-width: 0;
}

.footer-mark {
  margin-bottom: 1.5rem;
}

/* The mark's own ground is transparent and its wordmark is the brand red, so
   it sits straight on the band. No white plate behind it: that read as a
   sticker on the footer rather than as the shop's mark. */
.footer-logo {
  display: inline-block;
}

.footer-logo img {
  display: block;
  max-width: 132px;
  max-height: 44px;
  width: auto;
  height: auto;
}

.footer-wordmark {
  display: inline-block;
  font-size: 1.375rem;
  font-weight: 800;
  letter-spacing: 0.02em;
  color: #fff;
}

/* ------------------------------------------------------------------
 * Headings and links
 * ------------------------------------------------------------------ */

.footer-heading {
  margin: 0 0 1rem;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: #fff;
}

/* A short red rule under each heading, the one piece of brand colour that is
   not carrying text. */
.footer-heading::after {
  content: "";
  display: block;
  width: 26px;
  height: 2px;
  margin-top: 0.5rem;
  background-color: var(--simko-brand);
  border-radius: 2px;
}

.footer-list {
  margin: 0;
  padding: 0;
}

.footer-list li + li {
  margin-top: 0;
}

/* Padded to the 44px touch floor rather than sized to the text: these are the
   smallest targets on the page and they sit closest to the thumb. Trimmed to
   40px below sm -- see the phone block at the end of this section. */
.footer-list a {
  display: inline-flex;
  align-items: center;
  min-height: var(--simko-touch);
  padding: 0.25rem 0;
  font-size: 0.875rem;
  line-height: 1.4;
  color: #cfcfcf;
  text-decoration: none;
  transition: color var(--simko-speed) var(--simko-ease);
}

.footer-list a:hover,
.footer-list a:focus-visible {
  color: var(--simko-brand-light);
}

/* The 44px floor is there for a thumb. Where the pointer is a mouse there is
   no thumb, and four rows of it makes a column half as tall again as the text
   in it. */
@media (hover: hover) and (pointer: fine) {
  .footer-list a {
    min-height: 0;
    padding: 0.2rem 0;
  }
}

.site-footer a:focus-visible {
  outline: 2px solid var(--simko-brand-light);
  outline-offset: 3px;
  border-radius: 3px;
}

/* ------------------------------------------------------------------
 * The store's details (.footer-facts)
 *
 * Same shape as the contact page's .contact-fact -- a fixed-width icon, a
 * small label, the value under it -- so the two places the store's details
 * appear are read the same way.
 * ------------------------------------------------------------------ */

.footer-facts {
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.9rem;
}

.footer-fact {
  display: flex;
  gap: 0.75rem;
  align-items: flex-start;
}

.footer-fact > i {
  flex: 0 0 1.25rem;
  margin-top: 0.2rem;
  font-size: 0.8125rem;
  text-align: center;
  color: var(--simko-brand-light);
}

.footer-fact-body {
  min-width: 0;
}

.footer-fact-label {
  display: block;
  margin-bottom: 0.15rem;
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #8f8f8f;
}

.footer-fact-value {
  display: block;
  margin: 0;
  font-size: 0.875rem;
  font-style: normal;
  line-height: 1.55;
  color: #e6e6e6;
  text-decoration: none;
  transition: color var(--simko-speed) var(--simko-ease);
}

a.footer-fact-value:hover,
a.footer-fact-value:focus-visible {
  color: var(--simko-brand-light);
}

/* ------------------------------------------------------------------
 * The link columns (.footer-nav)
 * ------------------------------------------------------------------ */

/* One column on a phone. Two across fits, but there are three groups, so the
   third lands alone against an empty half -- and the pair that do share a row
   leave 'Customer Service' and 'Delivery Information' wrapping mid-phrase.
   Stacked, every heading and link gets the full width and reads as one list. */
.footer-nav {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 2rem 1.5rem;
}

.footer-column {
  min-width: 0;
}

/* ------------------------------------------------------------------
 * The bottom bar (.footer-bottom)
 * ------------------------------------------------------------------ */

.footer-bottom {
  padding: 1.25rem 0 1.5rem;
  border-top: 1px solid rgba(255, 255, 255, 0.1);
}

.footer-copyright {
  margin: 0;
  font-size: 0.8125rem;
  line-height: 1.5;
  color: #8f8f8f;
}

/* ------------------------------------------------------------------
 * Below sm: the same footer, less air
 *
 * Stacked, the three link groups are ten 44px rows plus three headings plus the
 * gaps between them -- about 630px of footer on a 411px phone, where the rows
 * read as far apart as the groups they belong to. Nothing moves and nothing is
 * hidden here; the rows come in to 40px, the headings sit closer to their lists
 * and the bands lose a little padding. About 140px back.
 * ------------------------------------------------------------------ */

@media (max-width: 767.98px) {
  .site-footer {
    margin-top: 24px;
  }

  .site-footer .footer-top {
    gap: 1.5rem;
    padding: 1.75rem 0 1.25rem;
  }

  .footer-mark {
    margin-bottom: 1rem;
  }

  .footer-facts {
    gap: 0.7rem;
  }

  /* The rule under a heading belongs to it, so both halves of the gap between
     heading and list come in together. */
  .footer-heading {
    margin-bottom: 0.6rem;
  }

  .footer-heading::after {
    margin-top: 0.4rem;
  }

  .footer-nav {
    gap: 1.25rem 1.5rem;
  }

  .footer-bottom {
    padding: 1rem 0 1.25rem;
  }
}

/* Guarded on hover, not just width: the (hover: hover) rule above drops the
   floor to nothing for a mouse, and a desktop window dragged narrower than sm
   should keep that rather than pick up a thumb's row height. 40px is under the
   44 Apple asks for and the 48dp Material asks for -- accepted deliberately,
   because ten rows at 44px is what made the list read as separate groups. */
@media (max-width: 767.98px) and (hover: none) {
  .footer-list a {
    min-height: 2.5rem;
    padding: 0.2rem 0;
  }
}

/* ------------------------------------------------------------------
 * Wider screens
 *
 * The brand column takes the room it needs for an address, and the three link
 * columns share what is left. Below md everything is stacked, brand and links
 * alike.
 * ------------------------------------------------------------------ */

@media (min-width: 768px) {
  .site-footer .footer-top {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.35fr);
    gap: 3rem;
    padding: 3rem 0 2.25rem;
  }

  .footer-nav {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* The link columns stay two across until lg. Three of them beside the brand
   column leaves each about 200px, and 'Delivery Information' and 'Customer
   Service' both wrap to two lines at that width -- a column of headings and
   links that each break mid-phrase reads as a mistake. */
@media (min-width: 992px) {
  .site-footer .footer-top {
    grid-template-columns: minmax(0, 0.75fr) minmax(0, 2fr);
    gap: 4rem;
    padding: 3rem 0 2.25rem;
  }

  .footer-nav {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .footer-bottom {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
  }
}

/* ---------------------------------------------------------------------------
   Services listing

   A partner card answers a different question from a product tile: not "what
   is this and can I buy it" but "who covers my area, from how much, and how
   much notice do they need". So these are wide stacked rows rather than a
   grid of squares -- the location and price line up down the page and can be
   compared by scanning one column instead of jumping between tiles.
   --------------------------------------------------------------------------- */

/* The state filter leads the page: on a Services category it is the first
   thing a customer needs, so it sits above the sort/limit toolbar rather than
   inside it. */
.service-filter {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
  margin-bottom: 1rem;
  padding: 0.85rem 1rem;
  border: 1px solid var(--simko-border);
  border-radius: 14px;
  background-color: var(--simko-tint);
}

.service-filter-label {
  margin: 0;
  font-size: 0.9375rem;
  font-weight: 700;
  color: var(--simko-ink);
  white-space: nowrap;
}

.service-filter-select {
  min-height: var(--simko-touch);
  width: auto;
  min-width: 12rem;
  padding: 0.35rem 2rem 0.35rem 0.75rem;
  border: 1px solid var(--simko-border);
  border-radius: var(--simko-radius);
  font-size: 0.9375rem;
}

.service-filter-clear {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--simko-brand);
  text-decoration: none;
}

.service-filter-clear:hover,
.service-filter-clear:focus-visible {
  color: var(--simko-brand-dark);
  text-decoration: underline;
}

.service-list {
  display: grid;
  gap: 0.75rem;
  margin-bottom: 1.5rem;
}

/* Three tracks on a wide screen -- thumbnail, the text, then the price and its
   button held together on the right so the money and the action read as one
   thing. Below `md` the aside drops under the text and goes full width, which
   is what makes the button comfortably tappable on a phone. */
.service-card {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  grid-template-areas:
    'figure body'
    'aside  aside';
  gap: 0.75rem 1rem;
  align-items: start;
  padding: 1rem;
  border: 1px solid var(--simko-border);
  border-radius: 14px;
  background-color: #fff;
  transition: border-color var(--simko-speed) var(--simko-ease), box-shadow var(--simko-speed) var(--simko-ease);
}

.service-card:hover {
  border-color: var(--simko-brand-light);
  box-shadow: 0 6px 18px rgba(26, 26, 26, 0.07);
}

.service-card-figure {
  grid-area: figure;
  display: block;
  overflow: hidden;
  border-radius: var(--simko-radius);
  background-color: #f4f4f4;
}

.service-card-image {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
}

.service-card-body {
  grid-area: body;
  min-width: 0;
}

.service-card-title {
  margin: 0 0 0.25rem;
  font-size: 1.0625rem;
  font-weight: 700;
  line-height: 1.3;
}

.service-card-title a {
  color: var(--simko-ink);
  text-decoration: none;
}

.service-card-title a:hover,
.service-card-title a:focus-visible {
  color: var(--simko-brand);
}

.service-card-location {
  margin: 0 0 0.35rem;
  font-size: 0.875rem;
  color: var(--simko-ink-muted);
}

.service-card-location i {
  margin-right: 0.2rem;
  color: var(--simko-brand);
}

/* Two lines of blurb is enough to tell partners apart; more and the cards stop
   being scannable as a column. */
.service-card-text {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--simko-ink-muted);
}

.service-card-notice {
  margin: 0.4rem 0 0;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--simko-ink-muted);
}

.service-card-aside {
  grid-area: aside;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--simko-border);
}

.service-card-price {
  margin: 0;
  font-size: 1.125rem;
  color: var(--simko-ink);
}

/* "from" is the whole point of the number -- a starting price, not the price
   of a fixed thing -- so it is set quietly beside it rather than hidden. */
.service-card-from {
  font-size: 0.8125rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--simko-ink-muted);
}

.service-card-price strong {
  font-weight: 800;
  color: var(--simko-brand);
}

.service-card-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--simko-touch);
  padding: 0.5rem 1.75rem;
  border-radius: var(--simko-radius);
  background-color: var(--simko-ink);
  color: #fff;
  font-weight: 700;
  text-decoration: none;
  transition: background-color var(--simko-speed) var(--simko-ease);
}

.service-card-btn:hover,
.service-card-btn:focus-visible {
  background-color: var(--simko-brand);
  color: #fff;
  text-decoration: none;
}

.service-card-btn:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

.simko-js .service-list.simko-reveal .service-card {
  opacity: 0;
  transform: translateY(22px);
  transition:
    opacity 480ms var(--simko-ease),
    transform 480ms var(--simko-ease);
  transition-delay: calc(100ms + (var(--card-index, 0) * 70ms));
}

.simko-js .service-list.simko-reveal-in .service-card {
  opacity: 1;
  transform: none;
}

@media (min-width: 768px) {
  .service-card {
    grid-template-columns: 120px minmax(0, 1fr) auto;
    grid-template-areas: 'figure body aside';
    align-items: center;
    gap: 1.25rem;
  }

  .service-card-aside {
    flex-direction: column;
    align-items: flex-end;
    justify-content: center;
    padding-top: 0;
    padding-left: 1.25rem;
    border-top: 0;
    border-left: 1px solid var(--simko-border);
  }

  .service-card-price {
    text-align: right;
    white-space: nowrap;
  }
}

/* ---------------------------------------------------------------------------
   Booking form

   Replaces the product page's cart for service listings. Two columns on a wide
   screen -- who you are booking on the left, when you need them on the right --
   collapsing to one on a phone with the partner's details first, so the
   customer can confirm they are on the right listing before filling anything
   in.
   --------------------------------------------------------------------------- */

.booking-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1rem;
  margin-bottom: 2rem;
}

.booking-alert {
  border-radius: 14px;
}

.booking-partner {
  padding: 1.25rem;
  border: 1px solid var(--simko-border);
  border-radius: 14px;
  background-color: var(--simko-tint);
}

/* The product page's gallery, reused. There it is a full-bleed column of its
   own; here it sits inside a bordered panel, so the stage gives back the
   negative inline margin that makes it bleed and takes the panel's corners
   instead. */
/* From lg the product page makes .product-gallery sticky so the picture
   follows the copy describing it. Here the whole partner panel is already
   sticky, and a second sticky inside it detaches the gallery from the panel:
   on scroll it slides down over its own title and price. Pinned back into
   flow -- the panel does the following. */
.booking-gallery {
  position: static;
  margin-bottom: 0.85rem;
}

.booking-gallery .product-gallery-stage {
  margin-inline: 0;
  overflow: hidden;
  border-radius: var(--simko-radius);
}

/* The product page scrolls its thumbnail strip sideways, which works in a
   column half the page wide. This panel is narrower than five thumbs, so the
   strip wraps instead -- a clipped thumbnail at the panel edge reads as a
   layout fault rather than as an invitation to scroll. */
.booking-gallery .product-gallery-thumbs {
  margin-top: 0.5rem;
  flex-wrap: wrap;
  overflow-x: visible;
}

.booking-gallery .product-gallery-empty {
  border-radius: var(--simko-radius);
}

.booking-partner-title {
  margin: 0 0 0.5rem;
  font-size: 1.25rem;
  font-weight: 800;
  line-height: 1.25;
  color: var(--simko-ink);
}

.booking-partner-meta {
  margin: 0 0 0.3rem;
  font-size: 0.875rem;
  color: var(--simko-ink-muted);
}

.booking-partner-meta i {
  width: 1rem;
  margin-right: 0.25rem;
  color: var(--simko-brand);
}

.booking-partner-price {
  margin: 0.85rem 0 0;
  font-size: 1.25rem;
}

.booking-partner-from {
  font-size: 0.8125rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--simko-ink-muted);
}

.booking-partner-price strong {
  font-weight: 800;
  color: var(--simko-brand);
}

.booking-partner-text {
  margin-top: 0.85rem;
  padding-top: 0.85rem;
  border-top: 1px solid var(--simko-border);
  font-size: 0.875rem;
  line-height: 1.55;
  color: var(--simko-ink-muted);
}

.booking-main {
  padding: 1.25rem;
  border: 1px solid var(--simko-border);
  border-radius: 14px;
  background-color: #fff;
}

.booking-title {
  margin: 0 0 0.35rem;
  font-size: 1.375rem;
  font-weight: 800;
  color: var(--simko-ink);
}

.booking-intro {
  margin: 0 0 1.25rem;
  font-size: 0.9375rem;
  color: var(--simko-ink-muted);
}

.booking-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1rem;
}

.booking-field {
  min-width: 0;
}

.booking-label {
  display: block;
  margin-bottom: 0.35rem;
  font-size: 0.875rem;
  font-weight: 700;
  color: var(--simko-ink);
}

.booking-optional {
  font-weight: 500;
  text-transform: lowercase;
  color: var(--simko-ink-muted);
}

.booking-form .form-control,
.booking-form .form-select {
  min-height: var(--simko-control-h);
  border: 1px solid var(--simko-border);
  border-radius: var(--simko-radius);
  font-size: 0.9375rem;
}

.booking-form textarea.form-control {
  min-height: 0;
}

.booking-form .form-control:focus,
.booking-form .form-select:focus {
  border-color: var(--simko-brand);
  box-shadow: 0 0 0 3px var(--simko-tint);
}

.booking-form .is-invalid {
  border-color: var(--simko-brand);
}

.booking-error {
  margin-top: 0.3rem;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--simko-brand);
}

.booking-help {
  margin-top: 0.3rem;
  font-size: 0.8125rem;
  color: var(--simko-ink-muted);
}

.booking-note {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  margin: 1.25rem 0;
  padding: 0.85rem 1rem;
  border-radius: var(--simko-radius);
  background-color: var(--simko-tint);
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--simko-ink-muted);
}

.booking-note i {
  margin-top: 0.15rem;
  font-size: 1.125rem;
  color: #25d366;
}

/* Off-screen rather than display:none: some bots skip hidden inputs, and a
   negative tabindex keeps it off the keyboard path either way. */
.booking-decoy {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.booking-submit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  width: 100%;
  min-height: 52px;
  padding: 0.5rem 2rem;
  border: 0;
  border-radius: var(--simko-radius);
  background-color: var(--simko-ink);
  color: #fff;
  font-size: 1rem;
  font-weight: 700;
  transition: background-color var(--simko-speed) var(--simko-ease);
}

.booking-submit i {
  font-size: 1.25rem;
}

.booking-submit:hover:not(:disabled),
.booking-submit:focus-visible:not(:disabled) {
  background-color: var(--simko-brand);
  color: #fff;
}

.booking-submit:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

.booking-submit:disabled {
  opacity: 0.55;
}

.simko-js .booking-layout.simko-reveal {
  opacity: 0;
  transform: translateY(20px);
  transition:
    opacity 480ms var(--simko-ease),
    transform 480ms var(--simko-ease);
}

.simko-js .booking-layout.simko-reveal-in {
  opacity: 1;
  transform: none;
}

@media (min-width: 576px) {
  .booking-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .booking-field-wide {
    grid-column: 1 / -1;
  }

  .booking-submit {
    width: auto;
  }
}

@media (min-width: 992px) {
  .booking-layout {
    grid-template-columns: 20rem minmax(0, 1fr);
    align-items: start;
    gap: 1.5rem;
  }

  .booking-partner {
    position: sticky;
    top: 1.5rem;
  }

  .booking-main {
    padding: 1.75rem;
  }
}

/* ==========================================================================
   Subscriptions and returns — hidden while neither feature is in use
   ==========================================================================

   Presentation-only suppression: no template, controller or route is touched
   and nothing is removed from the data, so switching either feature back on is
   a matter of deleting the selectors below. The pages themselves stay reachable
   by URL -- this hides the ways in, it is not access control.

   Safe to do from CSS for subscriptions because no product carries a plan
   (`product_subscription` is empty): checkout/cart.php:278 rejects an
   add-to-cart when a product HAS plans and none was posted, so if plans are
   ever attached to a product this block must go before that product is
   published, or its buy button breaks.

   Links are matched on their href: the account sidebar, the overview cards and
   core's own lists are all built from data, so there is no class or id to hang
   this on. Two URL shapes per route -- config_seo_url is on and
   startup/seo_url rewrites `account/subscription` and `account/returns` to
   their `subscriptions` / `returns` keywords, so live hrefs read
   `/subscriptions?language=...` and carry no `route=`; the query form is kept
   for when SEO URLs are off, and it is also the shape the order page's Return
   button keeps (`account/returns.add` has no keyword of its own).

   Every wrapper involved -- account nav row, overview card, stat tile, footer
   service link, core's plain list item -- is an <li> with the anchor as its
   direct child, so one `li:has(> a)` rule covers them all; hiding the anchor
   alone would leave an empty row behind. */

/* Product page: the whole plan block, so its heading goes with the select. */
.product-options:has(#input-subscription),
.product-option-note.subscription {
  display: none !important;
}

li:has(> a[href*="route=account/subscription"]),
li:has(> a[href*="/subscriptions?"]),
li:has(> a[href$="/subscriptions"]),
li:has(> a[href*="route=account/returns"]),
li:has(> a[href*="/returns?"]),
li:has(> a[href$="/returns"]),
a[href*="route=account/subscription"],
a[href*="/subscriptions?"],
a[href$="/subscriptions"],
a[href*="route=account/returns"],
a[href*="/returns?"],
a[href$="/returns"] {
  display: none !important;
}

/* An overview section left with no card but the hidden ones would otherwise
   render as a lone heading. */
.account-section:not(:has(.account-card-link:not([href*="route=account/subscription"]):not([href*="/subscriptions?"]):not([href$="/subscriptions"]):not([href*="route=account/returns"]):not([href*="/returns?"]):not([href$="/returns"]))) {
  display: none;
}

/* ==================================================================
 * Maintenance page (.maintenance-page)
 *
 * The shop with config_maintenance on. startup/maintenance sends every request
 * here -- category, basket, contact, the lot -- so the page is a dead end by
 * design, and its job is to say so warmly and hand over the ways out that are
 * not the website: WhatsApp, the phone and e-mail.
 *
 * One card, centred, on a tinted ground. Nothing here scrolls, so everything
 * fits inside a phone screen below the header: badge, heading, two short lines,
 * the buttons, and the retry link under them.
 * ================================================================== */

.maintenance-page {
  padding-bottom: 3rem;
}

.maintenance-card {
  position: relative;
  max-width: 44rem;
  margin: 0 auto;
  padding: 3rem 1.25rem 2.25rem;
  overflow: hidden;
  border: 1px solid var(--simko-border);
  border-radius: 16px;
  background-image: linear-gradient(180deg, var(--simko-tint), #fff 62%);
  text-align: center;
}

/* Three dots on the top edge. The card is otherwise a notice, and this is the
   one thing on it that says party shop rather than server. */
.maintenance-confetti {
  position: absolute;
  top: 1.1rem;
  left: 0;
  display: flex;
  justify-content: center;
  gap: 0.4rem;
  width: 100%;
}

.maintenance-confetti i {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background-color: var(--simko-brand);
  opacity: 0.35;
  animation: maintenance-pulse 1.8s var(--simko-ease) infinite;
}

.maintenance-confetti i:nth-child(2) {
  animation-delay: 0.22s;
}

.maintenance-confetti i:nth-child(3) {
  animation-delay: 0.44s;
}

/* Three dots taking it in turns is the shop saying it is working on it. The
   travel is 3px, so it reads as a heartbeat rather than a bounce. */
@keyframes maintenance-pulse {
  0%,
  100% {
    opacity: 0.28;
    transform: translateY(0);
  }

  50% {
    opacity: 1;
    transform: translateY(-3px);
  }
}

/* The wrench. Same size and treatment as the success page's tick, because the
   two pages are the same shape and should not look like different products. */
.maintenance-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 50%;
  background-color: var(--simko-brand);
  color: #fff;
  font-size: 1.375rem;
}

.maintenance-badge {
  margin: 1rem 0 0;
  color: var(--simko-brand);
  font-size: 0.6875rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.maintenance-title {
  margin: 0.35rem 0 0;
  font-size: 1.5rem;
  font-weight: 800;
  line-height: 1.25;
  color: var(--simko-ink);
}

.maintenance-lead {
  max-width: 46ch;
  margin: 0.6rem auto 0;
  color: var(--simko-ink-muted);
  font-size: 0.9375rem;
  line-height: 1.6;
}

/* The one worry a shopper who has already paid arrives with, answered before
   they have to ask it. */
.maintenance-note {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin: 1.25rem 0 0;
  padding: 0.5rem 0.9rem;
  border: 1px solid var(--simko-border);
  border-radius: 999px;
  background-color: #fff;
  color: var(--simko-ink);
  font-size: 0.8125rem;
  font-weight: 600;
  text-align: left;
}

.maintenance-note i {
  color: var(--simko-brand);
}

.maintenance-reach {
  margin-top: 1.75rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--simko-border);
}

.maintenance-reach-note {
  max-width: 42ch;
  margin: 0 auto;
  color: var(--simko-ink-muted);
  font-size: 0.875rem;
}

/* One button per row on a phone, full width: three buttons of three different
   widths, centred, read as three sizes of importance they do not have, and a
   thumb reaching across a 390px screen should not have to aim. They sit on one
   row from sm, where they fit. */
.maintenance-actions {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0.6rem;
  margin-top: 1.1rem;
}

.maintenance-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: var(--simko-touch);
  padding: 0.5rem 1.4rem;
  border: 1px solid var(--simko-border);
  border-radius: var(--simko-radius);
  background-color: #fff;
  color: var(--simko-ink);
  font-size: 0.9375rem;
  font-weight: 700;
  text-decoration: none;
  transition: background-color var(--simko-speed) var(--simko-ease), border-color var(--simko-speed) var(--simko-ease), color var(--simko-speed) var(--simko-ease);
}

.maintenance-btn.is-primary {
  border-color: var(--simko-brand);
  background-color: var(--simko-brand);
  color: #fff;
}

.maintenance-btn:hover,
.maintenance-btn:focus-visible {
  border-color: var(--simko-brand);
  color: var(--simko-brand);
  text-decoration: none;
}

.maintenance-btn.is-primary:hover,
.maintenance-btn.is-primary:focus-visible {
  border-color: var(--simko-brand-dark);
  background-color: var(--simko-brand-dark);
  color: #fff;
}

.maintenance-btn:focus-visible,
.maintenance-retry:focus-visible {
  outline: 2px solid var(--simko-brand);
  outline-offset: 2px;
}

/* A link, not a fourth button: it is the least useful thing on the card while
   the shop is closed, and the most useful the minute it opens. */
.maintenance-retry {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  min-height: var(--simko-touch);
  margin-top: 1.1rem;
  padding: 0 0.5rem;
  color: var(--simko-ink-muted);
  font-size: 0.875rem;
  font-weight: 600;
}

.maintenance-retry:hover,
.maintenance-retry:focus-visible {
  color: var(--simko-brand);
}

@media (min-width: 576px) {
  .maintenance-card {
    padding: 3.25rem 2.5rem 2.5rem;
  }

  .maintenance-title {
    font-size: 1.875rem;
  }

  .maintenance-actions {
    flex-flow: row wrap;
    justify-content: center;
  }
}

/* ------------------------------------------------------------------
 * Chrome that leads nowhere
 *
 * Every link in the header and the footer's link columns is intercepted by
 * startup/maintenance and answered with this page, so leaving them on the page
 * offers a shopper half a dozen ways to be told the same thing again. They are
 * hidden here rather than in the templates because header.twig and footer.twig
 * are shared with every open page; :has() keys the whole thing off the one
 * element that only exists while the shop is closed.
 *
 * What survives is what still works: the logo (which is itself a retry), the
 * footer's phone and e-mail rows, and the copyright line.
 *
 * The announcement bar goes with them. It advertises free delivery on orders
 * placed by 3pm, which is worse than noise on a shop that cannot take one.
 * ------------------------------------------------------------------ */

body:has(.maintenance-page) #announcement,
body:has(.maintenance-page) #menu,
body:has(.maintenance-page) .header-actions,
body:has(.maintenance-page) #header-search,
body:has(.maintenance-page) .footer-nav {
  display: none;
}

/* With the actions gone the logo is alone on the row, and left-aligned against
   a centred card below it. */
body:has(.maintenance-page) .header-bar {
  justify-content: center;
}

/* The footer's grid is brand column beside link columns from md. With the links
   gone the brand would sit in a third of the width with two thirds of nothing
   beside it, so it takes the whole row. */
body:has(.maintenance-page) .site-footer .footer-top {
  grid-template-columns: minmax(0, 1fr);
}

/* ------------------------------------------------------------------
 * Arrival
 * ------------------------------------------------------------------ */

.simko-js .simko-arrive.maintenance-card {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity 420ms var(--simko-ease), transform 420ms var(--simko-ease);
}

.simko-js .simko-arrive-in.maintenance-card {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .maintenance-confetti i {
    animation: none;
    opacity: 0.6;
  }

  .simko-js .simko-arrive.maintenance-card {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* ------------------------------------------------------------------
 * Floating chat button (.simko-chat)
 *
 * A WhatsApp pill pinned to the bottom-right corner of every storefront page.
 * Rendered by common/footer.twig, so it survives every route without a second
 * markup path.
 *
 * Brand red rather than WhatsApp's green: the mark is what a shopper
 * recognises, and a green lozenge is the one thing on the page that belongs to
 * nobody's palette. White on #da2229 is 4.95:1, past the 4.5:1 floor.
 *
 * Right, where every site puts its chat launcher: a shopper looks there for one
 * without being told. The cart drawer and the product page's sticky buy bar
 * also end at that edge, but both cover the button rather than fight it -- the
 * drawer outranks it, and the rule further down lifts it over the bar.
 * ------------------------------------------------------------------ */

.simko-chat {
  position: fixed;
  right: 1rem;
  bottom: calc(1rem + env(safe-area-inset-bottom));
  /* Over the page and the sticky buy bar (1030), under the cart drawer (1045)
     and the lightbox (1080): a shortcut off the page never reaches across
     something the shopper opened on purpose. */
  z-index: 1035;
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
  min-height: 56px;
  padding: 0 1.25rem;
  color: #fff;
  font-size: 0.9375rem;
  font-weight: 700;
  line-height: 1.2;
  background-color: var(--simko-brand);
  border-radius: 999px;
  box-shadow: 0 14px 30px -12px rgba(26, 26, 26, 0.55);
  transition: background-color var(--simko-speed) var(--simko-ease), transform var(--simko-speed) var(--simko-ease);
}

.simko-chat:hover,
.simko-chat:focus {
  color: #fff;
  background-color: var(--simko-brand-dark);
  transform: translateY(-2px);
}

.simko-chat:focus-visible {
  outline: 2px solid var(--simko-ink);
  outline-offset: 3px;
}

.simko-chat-icon {
  display: inline-flex;
  font-size: 1.625rem;
  line-height: 1;
}

/* The cookie notice is 150px of fixed banner across the bottom until it is
   answered, and the buy bar covers the corner on a product page that has been
   scrolled. Both are temporary, so the button steps over them for as long as
   they are there rather than being moved out of the corner for good. */
body:has(#cookie) .simko-chat {
  bottom: calc(158px + env(safe-area-inset-bottom));
}

@media (max-width: 991.98px) {
  body:has(.product-buybar.is-visible) .simko-chat {
    bottom: calc(5.25rem + env(safe-area-inset-bottom));
  }
}

/* The maintenance page already puts Chat on WhatsApp in the middle of its card,
   and it is the only thing on the page worth pressing. */
body:has(.maintenance-page) .simko-chat {
  display: none;
}

/* Below md the label runs most of the way across the screen, covering the
   content it is offering help with, so only the mark stays. */
@media (max-width: 767.98px) {
  .simko-chat {
    gap: 0;
    justify-content: center;
    width: 56px;
    padding: 0;
  }

  .simko-chat-label {
    /* Hidden to the eye, not to a screen reader: this text is the link's
       accessible name and there is no aria-label behind it. */
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

@media (prefers-reduced-motion: reduce) {
  .simko-chat {
    transition: background-color var(--simko-speed) var(--simko-ease);
  }

  .simko-chat:hover,
  .simko-chat:focus {
    transform: none;
  }
}

/* ------------------------------------------------------------------
 * Core's alerts (#alert)
 *
 * What still speaks here: wishlist and compare from a listing card, and any
 * other common.js answer the theme has not given a home of its own. Add to
 * cart no longer does -- productCart() and listingCart() open the cart drawer
 * instead, which shows the line that was added rather than describing it.
 *
 * Core put this 30% down the viewport, 600px wide, centred: a modal's position
 * without a modal's dismissal, landing over the grid or the form being read.
 * These are toasts in the bottom corner, out of the way of the content and of
 * the WhatsApp button, and they stack downward in the order they arrived.
 * ------------------------------------------------------------------ */

#alert {
  top: auto;
  right: 1rem;
  /* Clear of .simko-chat, which is 56px tall in the same corner and outranks a
     toast: a shortcut the shopper can always reach beats an answer that fades
     on its own after three seconds. */
  bottom: calc(1.75rem + 56px + env(safe-area-inset-bottom));
  left: auto;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  width: auto;
  max-width: min(24rem, calc(100vw - 2rem));
  margin-left: 0;
  /* The container spans its column whether or not it holds anything, so it is
     the alerts themselves that take the clicks. */
  pointer-events: none;
}

#alert .alert {
  pointer-events: auto;
  display: flex;
  align-items: flex-start;
  gap: 0.625rem;
  margin: 0;
  padding: 0.75rem 0.875rem;
  border: 1px solid var(--simko-border);
  border-left: 3px solid var(--simko-ink-muted);
  border-radius: var(--simko-radius);
  background-color: #fff;
  box-shadow: 0 12px 32px rgba(26, 26, 26, 0.16);
  color: var(--simko-ink);
  font-size: 0.875rem;
  line-height: 1.5;
  animation: simko-toast-in var(--simko-speed) var(--simko-ease) both;
}

/* Core's box-shadow rules are a coloured halo around a full-width box; the
   toast carries its colour on the left edge instead. */
#alert .alert-success,
#alert .alert-primary,
#alert .alert-info,
#alert .alert-secondary,
#alert .alert-warning,
#alert .alert-danger,
#alert .alert-light,
#alert .alert-dark {
  box-shadow: 0 12px 32px rgba(26, 26, 26, 0.16);
}

#alert .alert-success {
  border-left-color: #1f7a3d;
}

#alert .alert-danger,
#alert .alert-warning {
  border-left-color: var(--simko-brand);
}

#alert .alert i {
  margin-top: 0.125rem;
  font-size: 0.9375rem;
  line-height: 1.5;
}

#alert .alert-success i {
  color: #1f7a3d;
}

#alert .alert-danger i,
#alert .alert-warning i {
  color: var(--simko-brand);
}

/* The product name and the cart link core writes into the success message. */
#alert .alert a {
  color: var(--simko-brand);
  font-weight: 600;
}

/* Core's markup ends the alert with a .btn-close, which Bootstrap absolutely
   positions inside the padding of an .alert-dismissible. In a flex row it is
   the last item, sized down and pushed to the end. */
#alert .alert .btn-close {
  /* Bootstrap parks this in the corner of the padding box with position:
     absolute. Here it is simply the last item in the row. */
  position: static;
  flex: 0 0 auto;
  margin-left: auto;
  padding: 0.5rem;
  background-size: 0.625rem;
}

@keyframes simko-toast-in {
  from {
    opacity: 0;
    transform: translateY(0.5rem);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

@media (max-width: 575.98px) {
  #alert {
    right: 0.75rem;
    left: 0.75rem;
    bottom: calc(1.5rem + 56px + env(safe-area-inset-bottom));
    max-width: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  #alert .alert {
    animation: none;
  }
}
