/** Shopify CDN: Minification failed

Line 1965:0 Unexpected "}"

**/
/* 2026-05-15 (anti-jump #3): kill Pipeline-theme Flickity's
   padding-bottom reservation on the gallery wrapper. Pipeline sets
   `padding-bottom: var(--default-ratio)` (typically 100%) on
   `.flickity-viewport` to reserve a square placeholder while the
   slideshow loads. On product pages we REPLACE the slideshow with
   `.trieye-gallery` (a 4:3 main + 88px thumb grid, ~609px tall on
   desktop). The Flickity reservation makes the wrapper 763px tall
   briefly, then it shrinks to 609 when trieye-gallery's JS swap
   completes — a visible 154px collapse.
   The existing rule for this (around line 3611 in custom.css) is
   scoped to `@media (max-width: 768px)`. Same override applied
   here without a media wrapper so desktop benefits too. */
.product__media__wrapper .flickity-lock-height,
.product__media__wrapper .product__grid--slides,
.product__media__wrapper .product__grid--slides .flickity-viewport {
  padding-bottom: 0 !important;
  min-height: 0 !important;
}

/* 2026-05-15 (anti-jump): force vertical scrollbar always present.
   Without this, short pages render scrollbar-less, then when JS
   populates content and the page exceeds viewport height, the
   scrollbar appears — taking ~7px of horizontal space and shifting
   ALL page content right by 7px. Measured this exact shift via
   position-sampling on /products/the-view (every tracked element
   moved x: 113 → 120 at the moment the scrollbar appeared).
   Reserving the scrollbar gutter eliminates the universal jolt. */
html {
  overflow-y: scroll;
  scrollbar-gutter: stable;
}

/* Accordion */
/* 2026-05-12 (Quieter): accordion outer border softened. */
.config-accordion {
  border: 1px solid #e8e8e8;
  border-radius: 10px;
  overflow: hidden;
  margin-top: 18px;
}

/* 2026-05-12 (Quieter): YOUR BUILD accordion header — warm cream
   background instead of gray. Ties to the active-state palette
   ("this is about your selection"). Same content, just a softer
   tone. Letter-spacing nudged out so it reads as a section label
   rather than a button. */
.config-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 14px;
  cursor: pointer;
  background: #faf7f2;
  font-weight: 600;
  font-family: 'Space Grotesk', sans-serif;
  font-size: 13px;  /* 2026-05-20 Task 6: 12 → 13 */
  text-transform: uppercase;
  letter-spacing: 0.08em;
  transition: background 0.15s;
}
.config-header:hover {
  background: #f5f1ea;
}

/* Header puts the title and hint on the same row (hint sits to the right
   of the title) so the accordion button stays compact. The hint hides
   when the accordion is open since the body itself becomes self-explanatory.
   On narrow viewports we also hide the hint to keep the row from wrapping
   into two lines (which would defeat the compact-button intent). */
.config-header-text {
  display: flex;
  flex-direction: row;
  align-items: baseline;
  gap: 8px;
  flex: 1;
  min-width: 0;
}
.config-header-title {
  display: inline-block;
  flex-shrink: 0;
}
.config-header-hint {
  display: inline-block;
  font-size: 12px;  /* 2026-05-20 Task 6: 11 → 12 */
  font-weight: 400;
  color: #666;
  text-transform: none;
  letter-spacing: 0;
  font-family: 'Barlow', sans-serif;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
/* 2026-05-12 (Quieter): contextual hint internals — bold portion is the
   model identity (color/lens), separator slashes are quieter, add-on
   count chip is green (same money-back-to-you semantics). */
.config-header-hint b { color: #111; font-weight: 600; }
.config-header-hint .hint-sep { color: #b0b0b0; margin: 0 3px; font-weight: 400; }
.config-header-hint .hint-addons { color: #16a34a; font-weight: 600; margin-left: 6px; flex-shrink: 0; }
.config-accordion.open .config-header-hint {
  display: none;
}
/* 2026-05-12 (Quieter mobile): two-row header layout.
     Row 1: TITLE + PRICE + chevron (price is shrunk so it doesn't
            dominate the small-caps title)
     Row 2: hint (model line) using the full row width
   Implementation note: `.config-header-text` is a wrapper around
   title+hint by default. We collapse it with `display: contents` so
   its children become direct flex items of `.config-header`, then use
   `flex-wrap: wrap` + `order:` + `flex-basis: 100%` to land the hint
   on its own full-width row. */
@media (max-width: 480px) {
  .config-header {
    flex-wrap: wrap;
    align-items: center;
    row-gap: 4px;
  }
  .config-header-text {
    display: contents;
  }
  .config-header-title {
    flex: 1 1 auto;
    order: 1;
  }
  .config-right {
    flex: 0 0 auto;
    order: 2;
    /* Shrink so the price doesn't visually dominate the small-caps
       title. Mixed-case Barlow at 12px reads bigger than uppercase
       Space Grotesk at 12px — drop to 11px to balance. */
    font-size: 11px !important;
    gap: 8px;
  }
  .config-header-hint {
    flex: 1 1 100%;
    width: 100%;
    order: 3;
    display: block;
    white-space: normal;
    font-size: 11px;
    line-height: 1.35;
    text-overflow: clip;
    margin-top: 0;
  }
  .config-header-hint .hint-addons {
    margin-left: 4px;
  }
}

.config-right {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: 'Barlow', sans-serif;
  text-transform: none;
  letter-spacing: normal;
}

.config-arrow {
  transition: 0.3s;
}

.config-body {
  max-height: 0;
  overflow: hidden;
  transition: 0.3s;
  background: #fff;
}

.config-accordion.open .config-body {
  max-height: 1000px;
  padding: 14px;
}

/* Friendly intro paragraph at the top of the open accordion body —
   tells the user exactly what they're looking at and how to change
   the build. Sits above the auto-rendered config rows. */
/* 2026-05-12 (Quieter): explainer accent stripe shifts from purple
   #5b5bf7 to black, and background from cool gray to neutral. */
.config-explainer {
  margin: 0 0 12px;
  padding: 10px 12px;
  background: #f8f8f8;
  border-left: 3px solid #111;
  border-radius: 4px;
  font-size: 13px;  /* 2026-05-20 Task 6: 12 → 13 */
  line-height: 1.5;  /* 2026-05-20 Task 5: 1.45 → 1.5 for airier feel */
  color: #444;
  font-family: 'Barlow', sans-serif;
  text-transform: none;
  letter-spacing: 0;
  font-weight: 400;
}

.config-accordion.open .config-arrow {
  transform: rotate(180deg);
}

.config-items {
  font-size: 14px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.config-section-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: #999;
  margin-bottom: 2px;
  font-family: 'Space Grotesk', sans-serif;
}

/* 2026-05-12 (Quieter): "×N" quantity indicator next to addon title in
   the YOUR BUILD section when an accessory's stepper has qty > 1. */
.config-addon-qty,
.config-eyewear-qty {
  display: inline-block;
  margin-left: 4px;
  font-size: 11px;
  font-weight: 600;
  color: #666;
}

/* Eyewear-qty badge sits next to the bold lens title inside the
   composite row; nudge its weight + color slightly so it doesn't
   compete with the bold lens name. */
.config-row--composite .config-eyewear-qty {
  font-weight: 600;
  color: #555;
  vertical-align: baseline;
}

.config-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  font-size: 13px;
  line-height: 1.5;
}

/* 2026-05-12 (Quieter): composite row — replaces the 4 separate
   Lens/Frame/Size/Mirror rows. Title in bold + meta line below + price
   on the right. Used for the Glasses item in YOUR BUILD. */
.config-row--composite {
  align-items: flex-start;
  padding: 4px 0;
}
.config-row--composite .config-key {
  line-height: 1.4;
}
.config-row--composite .config-key b {
  color: #111;
  font-weight: 600;
}
.config-row--composite .config-val {
  font-weight: 600;
}

.config-key {
  color: #666;
  /* L25: long lens labels ("Spare lens: Clear · Left mirror · fits your
     Medium frame") wrapped weirdly when the row was a tight flex pair —
     the price would orphan to its own line with just "kr" visible. Letting
     the key shrink + wrap keeps the price column tight on the right edge. */
  flex: 1 1 auto;
  min-width: 0;
}

.config-val {
  color: #222;
  font-weight: 500;
  text-align: right;
  white-space: nowrap;
}

/* L25: price cell wrapper holds the optional struck original price + the
   current price. Inline-flex keeps them on the same row, right-aligned,
   with a small gap. */
.config-val-wrap {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  white-space: nowrap;
}
.config-val-orig {
  color: #999;
  font-weight: 500;
  font-size: 12px;
  text-decoration: line-through;
}

.config-row--subtotal {
  margin-top: 4px;
  padding-top: 6px;
  border-top: 1px solid #eee;
}

.config-row--subtotal .config-key { font-weight: 600; color: #222; }
.config-row--subtotal .config-val { font-weight: 600; }

/* L25 / L27: "You save X" summary row below Subtotal. Matches the
   sticky build drawer's savings line — same green (#16a34a) palette.
   The L25 warm-orange was misread as red / negative; positive-savings
   green reads as money-back-to-you. No minus prefix on the value
   either ("You save 218 kr", not "You save −218 kr"). */
.config-row--savings {
  margin-top: 2px;
  padding: 6px 0 2px;
  color: #16a34a;
}
.config-row--savings .config-key {
  color: #16a34a;
  font-weight: 500;
}
.config-val--savings {
  color: #16a34a;
  font-weight: 700;
}

.config-divider {
  height: 1px;
  background: #e0e0e0;
  margin: 8px 0;
}

/* Layout */
.px-block .block-parent {
  display: flex;
  justify-content: space-between;
  gap: 20px;
}

.px-wrap {
  margin-top: 20px;
}

/* Size Guide */
.sizeguidebtn {
  font-family: "Inter Tight", sans-serif;
  font-weight: 400;
  line-height: 1;
  text-decoration: underline;
  text-underline-offset: 3px;
  font-size: 14px;
  margin-top: 10px;
}

/* Addons */
.addons {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.addon-card {
  display: flex;
  justify-content: space-between;
  padding: 12px;
  border-radius: 8px;
  border: 1px solid #ddd;
  cursor: pointer;
  transition: 0.2s;
  background: #fff;
}

.addon-card.active:not([data-addon-category]) {
  background: #111;
  color: #fff;
  border-color: #111;
}

.addon-card.active:not([data-addon-category]) .compare {
  color: #bbb;
}

.addon-left strong {
  font-size: 16px;
  font-family: 'Inter Tight';
  font-weight: 600;
}

.addon-right {
    max-width: 80px;
    display: flex;
    justify-content: flex-end;
    align-items: center;
    width: 100%;
}


.compare {
  text-decoration: line-through;
  font-size: 12px;
  margin-right: 5px;
}

.badge {
  background: red;
  color: #fff;
  font-size: 10px;
  padding: 2px 6px;
  margin-left: 6px;
  border-radius: 4px;
}

span.price {
  font-weight: 700;
}

/* 60/40 grid split */
@media only screen and (min-width: 1100px) {
  .large-up--sixty { width: 60%; }
  .large-up--forty { width: 40%; }
}

/* 2026-05-12 (Quieter): lens-type group container.
   Default = 5 cols (The View's 5 lens types use full width on desktop).
   Adaptive `:has()` rules below override based on actual tile count
   so Classic (4 tiles) and Clip (2 tiles) also use the full width
   instead of leaving an empty cell on the right.
   On mobile the default drops to 3 cols so 5-up doesn't get cramped
   (View wraps to 3+2). The `:has()` rules still apply on mobile too —
   they have higher specificity than the bare `.px-groups` rule. */
/* 2026-05-15: switched from CSS Grid to FLEX on desktop. Two reasons:
   1. When `filterLensGroupsByMirror` hides some .px-group buttons via
      `.is-mirror-incompatible`, a grid keeps reserving column slots
      for the hidden items — visible buttons stay narrow with empty
      gaps. Flex with `flex: 1 1 0` makes the REMAINING visible
      buttons grow to fill the row, so 3-of-5 visible looks the same
      width as a native 3-button layout.
   2. The flex layout removes the need for `overflow-wrap: anywhere`
      mid-word breaks on "Photochromic" — with 3-4 visible buttons,
      each is wide enough that the full label fits on one line. */
.px-groups {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  /* 2026-05-15: center the row of buttons. With small tile counts (Clip's
     2 lens types, Classic's 4) the row doesn't fill the container — left-
     aligned buttons looked like a missing column on the right. Centering
     balances the row regardless of tile count. */
  justify-content: center;
}
.px-groups > .px-group {
  flex: 1 1 0;
  /* min-width must accommodate the widest single-word lens label
     ("Photochromic" ≈ 86px at 13px font) so we never have to break
     mid-word or ellipsise. */
  min-width: 90px;
}

@media (max-width: 767px) {
  /* Mobile reverts to grid for tighter control. Default: 3-col.
     `:has()` overrides below handle 2- and 4-tile products. */
  .px-groups {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 6px;
  }
  .px-groups > .px-group {
    flex: initial;
    min-width: 0;
  }
  /* 2 tiles (Clip-On: Polarized + Clear) → 2 cols on mobile */
  .px-groups:has(> .px-group:nth-child(2)):not(:has(> .px-group:nth-child(3))) {
    grid-template-columns: repeat(2, 1fr);
  }
  /* 4 tiles (The Classic) → 4 cols on mobile */
  .px-groups:has(> .px-group:nth-child(4)):not(:has(> .px-group:nth-child(5))) {
    grid-template-columns: repeat(4, 1fr);
  }
}

.px-groups button.px-group {
  max-width: none;
  width: 100%;
  min-width: 0;
}

/* 2026-05-12 (Quieter): lens-type tile — softened.
   Was: gray fill #f5f5f5 + 1px #e0e0e0 border, solid-black active state.
   Now: transparent + 1px #e8e8e8 border (default), warm-cream fill + 1px
   #111 border when active. Text stays #111 in active state (no white-on-
   black palette flip). Hover: slightly darker neutral border. */
.px-group {
  /* 2026-05-15 (desktop air): vertical padding bumped 14 → 16 so the
     icon + 2-line title + price stack has more breathing room.
     Horizontal padding tightened 16 → 6 to leave maximum room for
     long labels like "Photochromic" at the narrower 5-up column
     width. Combined with `.lens-card--text` losing its 6px
     horizontal padding too, the H5 now gets ~94px content width
     at 5-up (vs 86px needed for "Photochromic") — fits with buffer.
     Mobile keeps its own padding override in custom.css. */
  padding: 18px 6px;  /* 2026-05-20 Task 5: 16 → 18 (a touch more vertical air) */
  background: transparent;
  border: 1px solid #ececec;  /* 2026-05-20 Task 5: #e8e8e8 → #ececec (slightly softer) */
  border-radius: 10px;
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
  /* 2026-05-15 (centering pass): flex column so the .lens-card child
     vertically centers inside the button. With siblings in a row
     having `align-items: stretch` (default) on `.px-groups`, every
     button gets the same height — without this, the content anchors
     to the top of taller buttons. The `.px-group__badge` is
     `position: absolute` so it's not affected by this flex layout. */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.px-group:hover {
  border-color: #b0b0b0;
}

.px-group.active {
  background: #faf7f2;
  color: #111;
  border-color: #111;
}

/* 2026-05-12 (Quieter): "Bestseller" badge floats above the top edge
   of the Photochromic lens-type tile. Black on warm-cream so it reads
   as a curated callout, not a sale pill (sale-red would be off-brand
   for a non-discount badge). The lens-type tiles are position:relative
   already so absolute positioning anchors correctly; we add the rule
   defensively below in case any other variant relies on default. */
.px-group { position: relative; }
.px-group__badge {
  position: absolute;
  top: -9px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 3;
  background: #111;
  color: #fff;
  font: 700 9px/1 'Space Grotesk', sans-serif;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 3px 9px;
  border-radius: 3px;
  white-space: nowrap;
  pointer-events: none;
}
.px-group.active .px-group__badge {
  background: #faf7f2;
  color: #111;
  border: 1px solid #111;
  padding: 2px 8px;
}

/* 2026-05-12 (Quieter): mobile Bestseller badge — slightly smaller +
   tighter so it fits over the narrower mobile lens-type tiles (which
   drop to 3-col grid below 480px). */
@media (max-width: 480px) {
  .px-group__badge {
    font-size: 8.5px;
    padding: 2px 7px;
    top: -8px;
    letter-spacing: 0.06em;
  }
  .px-group.active .px-group__badge {
    padding: 1px 6px;
  }
}
.px-group.active .lens-card__name { color: #111; }
.px-group.active .lens-card__price { color: #111; font-weight: 700; }
.px-group.active .lens-card__icon img { filter: none; }

.px-group h5 {
    margin: 0;
    /* 2026-05-15: text-align was `left` — this was the ROOT CAUSE of
       the "text not centered in lens cards" bug. The parent
       `.lens-card--text` sets `text-align: center` and we want the H5
       text ("Standard", "Photochromic", etc.) to inherit that, but
       `.px-group h5` (specificity 0,1,1) was overriding the parent's
       center alignment. The H5 box itself was center-aligned via
       `align-items: center` + `width: 100%`, which made bounding-rect
       measurements look symmetric — but the TEXT inside the box was
       still left-anchored. Setting to `center` here aligns text
       inside the h5 explicitly. */
    text-align: center;
}

/* Lens card — compact column. Used on Classic/Clip (the View variant
   adds the `--text` modifier with its own rules further down). */
.lens-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    /* 2026-05-15: vertical centering added — content was previously
       anchored to the top of the card. With `.px-group` now also a
       flex column with centering, this is partly redundant but kept
       explicit so the card still centers if dropped into a non-flex
       parent (e.g., a future swatch layout). */
    justify-content: center;
    text-align: center;
    gap: 4px;
    padding: 4px 0;
}

.lens-card__icon {
    width: 22px;
    height: 22px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 2px;
}

.lens-card__icon img {
    width: 20px;
    height: 20px;
}

/* 2026-05-12 (Quieter): inline-SVG lens-type icons (Standard / High
   Contrast / Reflective / Polarized / Photochromic). Use currentColor
   so the icon takes on the surrounding text color — default #888-ish
   muted, active #111. */
.lens-card__icon svg.px-lens-icon {
    width: 22px;
    height: 22px;
    color: #555;
    transition: color 0.15s ease;
}
.px-group.active .lens-card__icon svg.px-lens-icon {
    color: #111;
}

.lens-card__name {
    font-size: 14px;  /* 2026-05-20 Task 6: 12 → 14 */
    font-weight: 700;
    margin: 0;
    line-height: 1.3;  /* 2026-05-20 Task 5: 1.2 → 1.3 for airier feel */
}

.lens-card__price {
    font-size: 14px;  /* 2026-05-20 Task 6: 13 → 14 */
    font-weight: 700;
    font-family: 'Inter Tight', sans-serif;
    opacity: 0.8;
    line-height: 1.35;  /* 2026-05-20 Task 5: explicit for consistency */
}

/* Active state */
.px-group.active .lens-card__icon img {
    filter: invert(1);
}

.px-group.active .lens-card__sub {
    opacity: 0.8;
}

/* Lens detail panel — Roka style */
/* ── Lens detail expanding panel (Direction B) ── */
.lens-detail {
    position: relative;
    margin-top: 12px;
    min-height: 0;
}
.lens-detail__pointer {
    position: absolute;
    top: -6px;
    width: 12px;
    height: 12px;
    background: #faf7f2;
    border: none;
    transform: rotate(45deg);
    transition: left 0.25s ease;
    left: 60px; /* default, repositioned by JS */
}
/* 2026-05-12 (Quieter): lens detail card — warm cream fill, no border.
   Pointer above matches. The Category badge inside switches from
   gray-on-white to white-on-cream-border to fit the warmer palette. */
.lens-detail__card {
    background: #faf7f2;
    border: none;
    border-radius: 10px;
    padding: 14px 18px 16px;
}
.lens-detail__header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 6px;
}
.lens-detail__best-for {
    font-size: 13px;
    font-weight: 600;
    color: #222;
}
.lens-detail__category {
    font-size: 10px;
    font-weight: 600;
    color: #444;
    background: #fff;
    border: 1px solid #e0d8cd;
    border-radius: 3px;
    padding: 2px 7px;
    letter-spacing: 0.04em;
}
.lens-detail__desc {
    font-size: 12.5px;
    line-height: 1.5;
    color: #666;
    margin: 0 0 12px;
}
.lens-detail__bar-wrap {
    margin: 0;
}
.lens-detail__bar-label {
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: #999;
    display: block;
    margin-bottom: 5px;
}
/* 2026-05-12 (Quieter): light-transmission bar — backfill is now a
   gradient from dark (left = low VLT, dark lens) to light (right =
   high VLT, clear lens). The gradient is the visual hint for "what
   you'd see at each end of the bar" — without it the bar reads as
   an abstract number scale. Markers sit on top, indicating the
   active variant's position(s). */
.lens-detail__bar {
    position: relative;
    height: 8px;
    background: linear-gradient(90deg, #2a2a2a 0%, #6b6b6b 40%, #cfcfcf 75%, #f4f4f4 100%);
    border-radius: 4px;
    overflow: hidden;
}
.lens-detail__bar-fill {
    position: absolute;
    top: -2px;
    bottom: -2px;
    height: 12px;
    background: #111;
    border: 2px solid #fff;
    border-radius: 3px;
    transition: width 0.3s ease, left 0.3s ease;
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.2);
    min-width: 8px;
}
.lens-detail__bar-fill--range {
    background: #111;
    border: none;
    height: 8px;
    top: 0;
    box-shadow: none;
}
.lens-detail__bar-fill--marker {
    /* Discrete marker for individual variants (Standard's Clear / Smoke
       split). Narrower than --range, sits on top of the gradient. */
    width: 10px !important;
    height: 14px;
    top: -3px;
    background: #111;
    border: 2px solid #fff;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
    transform: translateX(-50%);
}
.lens-detail__bar-values {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 5px;
    font-size: 11px;
    color: #666;
}
.lens-detail__bar-uv {
    font-weight: 600;
    color: #222;
    font-size: 10px;
    background: #e8f5e9;
    color: #2e7d32;
    padding: 1px 6px;
    border-radius: 3px;
}

/* Legacy classes kept for compatibility */
.lens-detail__specs { display: none; }
.lens-detail__icon { display: none; }
.lens-detail__conditions { display: none; }
.lens-detail__dot { display: none; }

/* 2026-05-12 (Quieter): the gradient transmission bar + its
   "LIGHT TRANSMISSION" label are hidden on ALL viewports — the
   numeric VLT range ("8–18% VLT") plus the Cat. badge in the header
   communicate the same info more directly. Bar visualization added
   complexity without proportional clarity gain (especially for the
   two-marker Standard variant, which was only ever one product's
   special case). */
.lens-detail__bar-label,
.lens-detail__bar {
  display: none;
}

/* 2026-05-12 (Quieter mobile): on mobile we also drop the prose
   description and tighten padding. Desktop keeps the description.
   Net mobile height: ~50px (was 157px). */
@media (max-width: 640px) {
  .lens-detail__card {
    padding: 10px 12px 10px;
  }
  .lens-detail__desc {
    display: none;
  }
  .lens-detail__header {
    margin-bottom: 6px;
  }
  .lens-detail__best-for {
    font-size: 12.5px;
    line-height: 1.3;
  }
  .lens-detail__bar-values {
    margin-top: 0;
  }
}
.lens-detail__transmission { display: none; }
.lens-detail__sub { display: none; }

.config-variant-info {
    color: #999;
    font-weight: 400;
    font-style: italic;
    font-size: 0.9em;
}

button.px-group.active img {
  filter: invert(1);
}

button.px-group.active h5 {
  color: #fff;
}

/* Sub buttons */
.px-sub {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 10px;
}

.px-sub-btn {
  padding: 8px 12px;
  border: 1px solid #ccc;
  border-radius: 6px;
  cursor: pointer;
}

.px-sub-btn.active {
  background: #000;
  color: #fff;
}

/* Rows */
.px-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 5px 0 12px;
}

/* Mirror Cards */
/* Clip size selector — Medium and Small shown side-by-side as toggle cards.
   Mirrors the .px-mirror-row card pattern (gray fill, black active state)
   for visual consistency across the configurator. */
.px-row.px-size-row--clip {
  display: flex;
  flex-wrap: nowrap;
  gap: 8px;
  width: 100%;
}
.px-row.px-size-row--clip button.px-btn {
  flex: 1 1 0%;
  min-width: 0;
  max-width: none;
  padding: 14px 16px;
  min-height: 64px;
  box-sizing: border-box;
  border: 1px solid #e0e0e0;
  background: #f5f5f5;
  border-radius: 10px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  font-family: 'Space Grotesk', sans-serif;
  transition: background 0.15s;
}
.px-row.px-size-row--clip button.px-btn strong {
  font-size: 14px;
  font-weight: 600;
}
.px-row.px-size-row--clip button.px-btn .px-btn__sub {
  font-size: 11px;
  color: #888;
  text-align: center;
  line-height: 1.3;
  word-wrap: break-word;
}
.px-row.px-size-row--clip button.px-btn.active {
  background: #222;
  color: #fff;
  border-color: #222;
}
.px-row.px-size-row--clip button.px-btn.active .px-btn__sub {
  color: rgba(255, 255, 255, 0.75);
}

/* 2026-05-12 (Quieter): Mirror Position row.
   Desktop: side-by-side (or 3-up when Right-Mirror is also shown),
            tight V0 compression.
   Mobile (≤640px): stacked vertically with more padding + bigger
            text, full-width touch targets.
   Equal-height stretch so wrapped qualifiers don't make buttons
   uneven. */
.px-row.px-mirror-row {
  display: flex;
  flex-wrap: nowrap;
  gap: 8px;
  width: 100%;
  align-items: stretch;
}
@media (max-width: 640px) {
  .px-row.px-mirror-row {
    flex-direction: column;
  }
}

/* 2026-05-12 (Quieter): mirror button base — transparent default,
   tight V0 padding, equal-height flex column.
   Border is 2px from the start (light gray for inactive) so the active
   state can flip border-color to #111 without changing layout. This
   keeps padding identical between states — content doesn't shift 1px
   when the user clicks. The `!important` on padding is needed because
   a legacy `@media (max-width:512px) .px-btn { padding: 4px !important }`
   rule in custom.css (originally for tiny frame thumbnails) would
   otherwise override us. */
.px-row.px-mirror-row button.px-btn {
  flex: 1 1 0%;
  min-width: 0;
  max-width: none !important;
  border: 2px solid #e8e8e8 !important;
  background: #fff;
  padding: 10px 12px !important;
  min-height: auto;
  overflow: hidden;
  border-radius: 10px;
  transition: background 0.15s, border-color 0.15s;
}

/* 2026-05-12 (Quieter): active mirror button — same 2px border (color
   only) on warm cream fill. Padding unchanged from inactive so the
   text doesn't shift position on toggle.
   Selector includes both classes (.px-btn.active) so its specificity
   (0,4,1) beats the base rule's (0,3,1). Without that, the base rule's
   border-color #e8e8e8 wins and the active button never turns black. */
.px-row.px-mirror-row button.px-btn.active {
  background: #faf7f2 !important;
  color: #111;
  border-color: #111 !important;
  padding: 10px 12px !important;
}

.px-row.px-mirror-row button.px-btn.active .mirror-card h5,
.px-row.px-mirror-row button.px-btn.active .mirror-card p {
  color: inherit;
}
.px-row.px-mirror-row button.px-btn.active .mirror-card p {
  color: #555;
}

.px-row.px-mirror-row button.px-btn.active .mirror-card h6 {
  border-color: rgb(17 17 17 / 12%);
}

/* 2026-05-12 (Quieter mobile): mirror buttons compressed for mobile
   vertical-space budget. Stacked layout with tight padding + smaller
   text. Title-to-body margin tightens so each card is ~52px tall
   instead of ~72px (saves ~40px for 2 stacked cards). The qualifier
   text truncates to one line — the title (Left / Right / Dual)
   carries the primary meaning. */
@media (max-width: 640px) {
  /* Both active + inactive get identical padding so toggling state
     doesn't shift the text 1px. Border thickness is constant (2px)
     across states — only the color flips. */
  .px-row.px-mirror-row button.px-btn,
  .px-row.px-mirror-row button.px-btn.active {
    padding: 11px 14px !important;
  }
  .mirror-card h5 {
    font-size: 14px !important;
    margin-bottom: 2px !important;
  }
  .mirror-card p {
    font-size: 11.5px !important;
    line-height: 1.3 !important;
    /* 2026-05-15: ellipsis REMOVED — let mirror labels ("Left Mirror",
       "Right Mirror") wrap at whitespace if a narrow mobile viewport
       can't fit them on one line. */
    white-space: normal;
  }
}

/* 2026-05-12 (Quieter, re-revised): the counter-traffic mirror is
   HIDDEN by default. Norway visitor (right-hand traffic) sees only
   Left + Dual; UK/AU visitor sees Right + Dual. The geo-locked third
   side is revealed by clicking the `.mirror-footnote__switch` link
   ("Switch to Right Mirror for UK / Australia →"), which adds
   `show-locked` to the container.
   Earlier in the day this hide was temporarily removed because Dual
   was also being hidden when OOS — fix shipped to keep Dual always
   visible, but went one step too far and also exposed Right.
   User clarification: "right mirror show when i start the page... i
   should only see left and dual since i'm in norway." */
.px-row.px-mirror-row button[data-mirror-locked] {
  display: none;
}
.px-row.px-mirror-row.show-locked button[data-mirror-locked] {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}

/* 2026-05-12 (Quieter): switch link below the mirror buttons —
   recommendation copy + action. Replaces the previous .px-size-expand-
   link styling reused on the mirror-footnote (was blue underlined).
   Now: two-line p with the action as an inline link inside. */
/* 2026-05-12 (Quieter, re-revised): swap link footnote restored —
   counter-traffic mirror is hidden by default, customer clicks the
   switch link to reveal. (Earlier today this was hidden; reverted
   per user feedback "i should only see left and dual since im in
   norway.") */
.mirror-footnote {
  font-size: 11px;
  color: #666;
  line-height: 1.5;
  margin: 12px 0 0;
}
.mirror-footnote__switch {
  color: #111;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
  font-weight: 500;
}
.mirror-footnote__switch:hover {
  text-decoration-thickness: 2px;
}
/* 2026-05-12 (Quieter mobile): hide the recommendation sentence on
   mobile to save another line of vertical space. The swap link
   ("Switch to Right Mirror for UK / Australia →") still shows — it's
   the actionable part. Customers who want context have the mirror
   card description directly above. The recommendation sentence is
   wrapped in <span class="mirror-footnote__recommend"> by the Liquid
   and by swapSingleSideMirror() so this targets both initial render
   and post-swap re-renders. */
@media (max-width: 640px) {
  .mirror-footnote {
    margin-top: 8px;
  }
  .mirror-footnote__recommend {
    display: none;
  }
}

/* 2026-05-12 (Quieter): model line ("MODEL  Matte Black/Polarized
   Smoke · Left/M145") — written by JS into [data-model-line]. Was a
   plain 11px gray line; now styled as a "tracked label + readable
   content" pattern. JS in Pass 3 writes the formatted HTML. Until
   then this style applies to whatever the JS writes today. */
.px-model-line {
  display: block;
  font-size: 13px;
  font-family: 'Inter Tight', sans-serif;
  color: #222;
  line-height: 1.4;
  margin: 14px 0 4px;
  /* 2026-05-12 (Quieter): override the parent's text-transform:
     uppercase that bled in from the .px-block header rules. Model
     line shows variant titles ("Matte Black", "Standard Smoke")
     which read correctly in mixed case. The LABEL ("Model") stays
     uppercase via its own rule. */
  text-transform: none;
  letter-spacing: 0;
}
.px-model-line__name, .px-model-line__spec {
  text-transform: none;
  letter-spacing: 0;
}
.px-model-line__label {
  font: 600 11px/1 'Space Grotesk', sans-serif;
  color: #888;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  margin-right: 10px;
}
.px-model-line__name {
  font-weight: 600;
  color: #111;
}
.px-model-line__sep {
  color: #b0b0b0;
  margin: 0 4px;
  font-weight: 400;
}
.px-model-line__spec {
  color: #666;
  font-weight: 500;
  margin-left: 10px;
  padding-left: 12px;
  border-left: 1px solid #ddd;
}

/* 2026-05-12 (Quieter mobile): the model line is long ("MODEL Matte
   Black / Photochromic Smoke 0–3 / Left / M145") and wraps badly on
   mobile — sometimes mid-word ("0–\n3"). Force a clean break using
   CSS Grid:
     Row 1, col 1: LABEL  ("MODEL")
     Row 1, col 2: NAME   ("Matte Black / Photochromic Smoke 0–3")
     Row 2, col 2: SPEC   ("Right / M145")  ← aligns under NAME
   Spec lands on its own row, indented to where the name starts (not
   flush left under the label). Each variant produces the same 2-line
   layout regardless of name length, so card heights match. The
   vertical divider is dropped — redundant with the line break. */
@media (max-width: 480px) {
  .px-model-line {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: baseline;
    row-gap: 2px;
  }
  .px-model-line__label {
    grid-column: 1;
    grid-row: 1;
  }
  .px-model-line__name {
    grid-column: 2;
    grid-row: 1;
    white-space: nowrap;
  }
  .px-model-line__spec {
    grid-column: 2;
    grid-row: 2;
    margin-left: 0;
    padding-left: 0;
    border-left: 0;
  }
}

/* 2026-05-12 (Quieter): mirror card content — left-align, tight V0
   vertical rhythm (title above qualifier with 1px margin), gray
   qualifier for hierarchy. */
.mirror-card {
  overflow: hidden;
  text-align: left;
  word-break: break-word;
}

.mirror-card h5 {
  font-size: 14px;
  font-family: 'Inter Tight', sans-serif;
  font-weight: 600;
  margin-bottom: 1px;
  line-height: 1.15;
  color: #222;
  /* 2026-05-12: override the theme's global `h5 { text-transform: var(--FONT-HEADING-TRANSFORM) }`
     rule. Without this, "Left Mirror" / "Dual Mirror" render as
     "LEFT MIRROR" / "DUAL MIRROR" — too shouty for the quieter palette. */
  text-transform: none;
  letter-spacing: 0;
}

.mirror-card p {
  font-size: 11px;
  text-align: left;
  color: #888;
  margin: 0;
  line-height: 1.3;
  word-wrap: break-word;
}

.mirror-card h6 {
  margin-top: 6px;
  padding-top: 6px;
  border-top: 1px solid hsl(0deg 0% 13% / 15%);
  font-size: 11px;
}

/* Variant */
.varient-title-sub {
    display: flex;
    justify-content: space-between;
    gap: 8px;
    flex: 1;
}

span.px-price {
  font-size: 14px;
  font-family: 'Inter Tight';
  font-weight: 700;
}

/* Buttons — base */
.px-btn {
    padding: 10px;
    border: 1px solid #ccc;
    border-radius: 6px;
    cursor: pointer;
    max-width: 90px;
    width: 100%;
    min-height: auto;
    /* L28 (D-CAT-TILE): allow absolute-positioned cat badge inside. */
    position: relative;
}

/* Model thumbnail buttons — square with image */
.px-size-group .px-btn {
    padding: 4px;
    aspect-ratio: 1 / 1;
}

.px-size-group .px-btn .px-img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 4px;
    aspect-ratio: 1 / 1;
    transition: transform 0.15s ease, filter 0.15s ease;
}

/* 2026-05-20 — Removed the 0.88 scale-down on Small tiles. Per user
   ("if you see on the smaller eyewear. they have some padding or
   something. make so they are same size") the customer reads the
   shrunken thumbnail as broken styling rather than as a size hint —
   the M / S pill in the corner already communicates the size
   difference unambiguously. Keeping the thumbnails uniform size
   makes the picker grid feel deliberate instead of glitchy.

   Was: .px-size-group .px-btn:has(.px-btn__size-pill.is-small) .px-img
        { transform: scale(0.88); }
*/

/* 2026-05-14: Photochromic 0–2 vs 0–3 visual differentiation.
   0–2 (lighter cat range) gets a subtle brightness lift + slightly
   reduced contrast to suggest "this lens doesn't darken as much" —
   helps customers tell the two cat ranges apart at thumbnail size
   even when the photography is identical (e.g. white-frame variants
   share the same source image). Targets both hyphen and en-dash
   spellings since the variant titles use the typographic en-dash. */
.px-size-group .px-btn[data-lens*="0-2"] .px-img,
.px-size-group .px-btn[data-lens*="0–2"] .px-img {
    filter: brightness(1.08) contrast(0.94);
}

/* L28 (D-CAT-TILE) + 2026-05-12 (Quieter): Cat. badge on photochromic
   variant tiles. Customers need to distinguish 0–2 vs 0–3 vs 0–3 Full
   Spectrum at thumbnail size — both lens images look near-identical.
   2026-05-12 update: badge now CENTERED horizontally at the top of the
   tile (was top-left). Drops the "Cat." prefix — content is short
   enough that "0–3" / "0–2" reads clean. Pill is white-on-dark with
   thin backdrop blur for legibility over any photo. */
.px-btn__cat {
    position: absolute;
    top: 6px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 2;
    padding: 3px 8px;  /* 2026-05-20 Task 5: 2px 7px → 3px 8px (airier) */
    background: rgba(255, 255, 255, 0.95);
    color: #111;
    border-radius: 3px;
    font-family: 'Space Grotesk', sans-serif;
    font-size: 11px;  /* 2026-05-20 Task 6: 10 → 11 */
    font-weight: 700;
    letter-spacing: 0.02em;
    line-height: 1.2;
    pointer-events: none;
    white-space: nowrap;
    -webkit-backdrop-filter: blur(2px);
    backdrop-filter: blur(2px);
}
/* L36: badge stays black-on-white regardless of tile state. The L28
   active-state invert was distracting — every photochromic click made
   the badge flip palette. The black pill on the active dark tile is
   still readable (white text on dark badge sits inside the otherwise-
   dark active tile fine), and the customer's eye stays on the photo. */
.px-size-group .px-btn--sold-out .px-btn__cat {
    opacity: 0.55;
}

/* 2026-05-12 (Quieter): size-info row holds the Medium label + Size
   Guide button on the same line. Was a standalone .px-size-info; now
   wrapped in .px-size-info-row for the flex pairing. The standalone
   .px-size-info below (used for Small) keeps the old standalone style. */
.px-size-info-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin: 16px 0 8px;
}
.px-size-info-row .px-size-info { margin: 0; }

/* Size section: expand/collapse for Small */
.px-size-info {
    font-size: 15px;  /* 2026-05-20 Task 6: 14 → 15 */
    color: #222;
    font-family: 'Space Grotesk', sans-serif;
    font-weight: 600;
    margin: 16px 0 8px;
    line-height: 1.3;
}
.px-size-info span {
    font-weight: 400;
    color: #888;
    font-size: 13px;  /* 2026-05-20 Task 6: 12 → 13 */
}
/* 2026-05-12 (Quieter): Small-expand link — was blue (#3b82f6),
   now black underlined to match the quieter palette. The link text is
   driven by JS and changes with active lens group ("Polarized also
   comes in Small..." vs "Hide Small options"). */
.px-size-expand-link {
    font-size: 13px;  /* 2026-05-20 Task 6: 12 → 13 */
    color: #111;
    cursor: pointer;
    margin-top: 8px;
    display: inline-block;
    text-decoration: underline;
    text-underline-offset: 3px;
    font-weight: 500;
}
.px-size-expand-link:hover {
    text-decoration-thickness: 2px;
}
.px-size-section-small {
    display: none;
    margin-top: 4px;
}
.px-size-section-small.is-open {
    display: block;
}
.px-size-section-small .px-size-group {
    margin-top: 0;
}

.px-btn__label {
    font-size: 12px;  /* 2026-05-20 Task 6: 11 → 12 */
    word-break: break-word;
    line-height: 1.2;
}

.px-size-group .px-row {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* 2026-05-12 (Quieter): active frame tile — 2px black border on warm-
   cream fill. Padding shrinks by 1px so total tile size is unchanged
   between states (no layout shift on click). */
.px-btn.active {
  background: #faf7f2;
  color: #111;
  border: 2px solid #111;
  padding: 9px;
}
.px-size-group .px-btn.active {
  padding: 3px;
}

.px-btn.hide {
  display: none !important;
}

/* 2026-05-12 (Quieter): sold-out frame tile — light white-fade overlay
   instead of the previous 60% grayscale + diagonal slash + 60% opacity.
   The image stays visible (slight saturation drop only); a 28% white
   overlay tells the customer the tile is paused without hiding the
   product. Caption sits at the bottom in dark text with a soft text-
   shadow so it reads on any color. Stays clickable so the L27
   alternatives chip mechanism still surfaces a replacement. */
.px-btn--sold-out {
  position: relative;
  opacity: 1;
  cursor: pointer;
  overflow: hidden;
}
.px-btn--sold-out .px-img {
  filter: saturate(0.7);
}
.px-btn--sold-out::after {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(255, 255, 255, 0.28);
  border-radius: 6px;
  pointer-events: none;
  z-index: 2;
}
.px-sold-out-label {
  position: absolute;
  bottom: 5px;
  left: 0;
  right: 0;
  font-size: 9.5px;
  font-weight: 700;
  color: #111;
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  text-shadow: 0 1px 1px rgba(255, 255, 255, 0.8);
  z-index: 3;
  padding: 1px 0;
  background: transparent;
}
.px-btn--sold-out.active {
  opacity: 1;
  border-color: #111;
  border-width: 2px;
  padding: 3px;
}

/* Notify Me button — HIDDEN. Klaviyo's Back-in-Stock app auto-injects its
   own button below the .px-oos-info text, so showing our custom button
   plus Klaviyo's resulted in two duplicate notify buttons. The OOS info
   text ("<variant> is currently out of stock — get notified below") plus
   Klaviyo's injected button is sufficient. The class is still added by
   the configurator JS (which we don't touch); we just hide it visually. */
.px-notify-btn {
  display: none !important;
}

/* 2026-05-12: hide Pipeline-native "Only N left" countdown widget.
   The configurator owns its own .px-low-stock banner (amber pill below
   YOUR BUILD), which shows the same info with the consistent palette.
   Showing both = duplicate stock message between YOUR BUILD and the
   cart row. */
.variant__countdown { display: none !important; }

/* Low stock indicator */
.px-low-stock {
  font-size: 13px;
  color: #e97316;
  font-weight: 600;
  padding: 8px 12px;
  text-align: left;
  background: #fff7ed;
  border-radius: 6px;
  border: 1px solid #fed7aa;
  margin-bottom: 8px;
}
.px-low-stock.px-low-stock--out {
  color: #dc2626;
  font-weight: 600;
  background: #fef2f2;
  border-color: #fecaca;
}
.px-low-stock__dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  background: #e97316;
  border-radius: 50%;
  margin-right: 6px;
  vertical-align: middle;
  animation: px-pulse 1.5s ease-in-out infinite;
}
@keyframes px-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.4; }
}

/* OOS info above Notify Me button */
.px-oos-info {
  font-size: 13px;
  color: #666;
  text-align: center;
  padding: 8px 0 4px;
  line-height: 1.4;
}
.px-oos-info strong {
  color: #222;
  font-weight: 600;
}
.px-oos-restock {
  font-size: 12px;
  color: #888;
  font-weight: 400;
  font-style: italic;
}

/* Prominent inline OOS banner — shown above YOUR CONFIGURATION
   when the selected variant is unavailable. Replaces the previous
   small "Item is out of stock" text as the primary OOS signal. */
.px-oos-banner {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin: 12px 0;
  padding: 14px 16px;
  background: #fef2f2;
  border: 1px solid #fecaca;
  border-radius: 10px;
  color: #991b1b;
}
.px-oos-banner[hidden] { display: none; }
.px-oos-banner__icon {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: #fee2e2;
  color: #dc2626;
}
.px-oos-banner__text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  line-height: 1.35;
}
.px-oos-banner__title {
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.01em;
  color: #991b1b;
}
.px-oos-banner__sub {
  font-size: 13px;
  color: #7f1d1d;
}

/* 2026-05-12 (Quieter): OOS mirror buttons are now SELECTABLE so the
   customer can click an out-of-stock side to register for Notify Me.
   Previously `pointer-events: none` made the buttons fully inert —
   customers couldn't even hover or click. With the click enabled, the
   click handler sets state.mirror, filterAndAutoSelect detects the
   variant is OOS (existsOos branch), and sets `_mirrorOosGeolock` so
   the cart button renders as "Notify Me". Visual differentiation
   stays: lower opacity + lighter border + the "Out of stock" stock
   indicator chip inside the card. */
.px-mirror--oos {
  opacity: 0.7;
  position: relative;
  border-color: #d1d5db !important;
  cursor: pointer;
}
.px-mirror--oos.active {
  border-color: #111 !important;
  opacity: 1;
}

/* 2026-05-15 (bug fix): the View snippet iterates `[data-mirror]` to
   add/remove `px-mirror--oos` on the INLINE mirror buttons (which
   are hidden on The View because the strip owns the mirror UI).
   But the strip's Single/Dual buttons ALSO carry `data-mirror=…`
   attributes for the strip's own click-forwarding logic — so the
   selector grabs them too and stamps OOS styling onto them.
   Reported symptom: on Reflective the Dual button is opacity 0.7
   (looks disabled) and users don't realize they can click it. In
   fact the click DOES work — `forwardToExisting()` auto-corrects to
   a Dual-compatible variant in the same lens group.
   This override neutralizes the OOS visual ONLY when applied to a
   strip button, so the strip's Dual stays full-opacity and looks
   clickable. The inline buttons (hidden anyway on View) still get
   the OOS treatment as before. */
.view-mirror-strip__btn.px-mirror--oos {
  opacity: 1;
  border-color: inherit !important;
}
/* 2026-05-12 (Quieter): mirror buttons reserve space for the stock
   indicator so buttons stay the SAME height whether they're in OOS
   state or available. Without this reservation, adding the indicator
   on click / state change made the button grow taller, causing the
   row to "jump" visually.

   .mirror-card uses an empty pseudo-element to reserve the indicator
   row's height. The real .mirror-stock-indicator slots into the same
   space when present. Net height: identical in both states. */
.mirror-card::after {
  content: '';
  display: block;
  height: 14px;
  margin-top: 4px;
}
.mirror-card:has(.mirror-stock-indicator)::after {
  display: none;
}

.mirror-stock-indicator {
  display: block;
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  margin-top: 4px;
  height: 14px;
  line-height: 14px;
}
.mirror-stock-indicator--oos {
  color: #dc2626;
}
.mirror-stock-indicator--available {
  color: #16a34a;
}

/* OOS Alternatives Panel */
.px-alternatives {
  margin-top: 12px;
  padding: 14px 16px;
  background: #f8f8f8;
  border: 1px solid #e5e5e5;
  border-radius: 10px;
}
.px-alternatives__header {
  margin-bottom: 8px;
}
.px-alternatives__oos-label {
  font-size: 13px;
  color: #666;
  line-height: 1.4;
}
.px-alternatives__title {
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #222;
  margin-bottom: 10px;
  font-family: 'Space Grotesk', sans-serif;
}
.px-alternatives__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.px-alt-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  background: #fff;
  border: 1px solid #ddd;
  border-radius: 20px;
  cursor: pointer;
  font-size: 13px;
  font-family: 'Inter Tight', sans-serif;
  font-weight: 500;
  color: #222;
  transition: all 0.15s;
}
.px-alt-chip:hover {
  border-color: #222;
  background: #222;
  color: #fff;
}
.px-alt-chip__change {
  font-size: 10px;
  opacity: 0.6;
}
.px-alt-chip:hover .px-alt-chip__change {
  opacity: 0.8;
}

/* Headings */
/* 2026-05-12 (Quieter): section titles ("CHOOSE YOUR TYPE",
   "REAR-VIEW MIRROR POSITION", etc.) — was 14px 600 near-black.
   Now 11px 600 tracked-out gray. Reads as a quiet label rather than
   a heavy heading — matches the rest of the page's rhythm. */
.px-block h4,
.px-lens h4,
.px-wrap h4 {
  font-size: 11px;
  color: #888;
  font-family: 'Space Grotesk', sans-serif;
  margin: 22px 0 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  line-height: 1;
}

.px-model-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
}

#px-color-title {
  font-size: 13px;
  font-weight: 500;
  text-transform: none;
  letter-spacing: 0;
  margin: 16px 0 8px;
  color: #444;
}

.px-model-header h4 {
  margin: 20px 0 10px;
  flex: 1;
  min-width: 0;
}

.px-model-label {
  font-size: 14px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.sizeguidebtn {
  font-size: 12px;
  color: #222;
  text-decoration: underline;
  background: none;
  border: none;
  cursor: pointer;
  white-space: nowrap;
  flex-shrink: 0;
  padding: 0;
}

/* Size Group */
.px-size-group h5 {
  font-size: 12px;
  font-weight: 500;
  color: rgb(34 34 34 / 80%);
  font-family: 'Space Grotesk';
}

/* Legacy icon row — kept for backwards compat */
.px-groups .icon-title-row {
  display: flex;
  gap: 8px;
  margin-bottom: 8px;
  padding-bottom: 8px;
  border-bottom: 1px solid rgb(34 34 34 / 15%);
}

button.px-group.active .icon-title-row {
  border-color: rgb(255 255 255 / 15%);
}

/* Narrow configurator — when using 2/3 or 3/4 gallery width */
/* Uses container query if supported, falls back to media query */

@media (max-width:1380px){
.varient-title-sub {
    align-items: flex-start;
    gap: 8px;
    width: 100%;
    flex-direction: column;
}

.product__icon-item {
    flex: 1;
    flex-direction: column;
    text-align: center;
}

/* Compact lens card in narrow layout */
.px-group {
    padding: 12px 14px;
}

.lens-card .leans-row {
    gap: 6px;
}

.px-groups .icon-title-row {
    margin-bottom: 8px;
    padding-bottom: 8px;
}

.px-group h5 {
    font-size: 13px;
    margin-bottom: 2px;
}

span.px-price {
    font-size: 14px;
}

.lens-card p {
    font-size: 12px;
    line-height: 1.4;
    margin-top: 4px;
}

/* Mirror cards: compact */
.px-row.px-mirror-row button.px-btn {
    padding: 10px;
    max-width: none;
    min-height: auto;
}

.mirror-card h5 {
    font-size: 13px;
}

.mirror-card p {
    font-size: 11px;
}

.mirror-card h6 {
    font-size: 12px;
    margin-top: 6px;
    padding-top: 6px;
}

/* Model buttons */
.px-size-group .px-btn {
    max-width: 80px;
    padding: 3px;
}

/* Headings: tighter */
.px-block h4, .px-lens h4, .px-wrap h4 {
    font-size: 14px;
    margin: 16px 0 8px;
    text-align: left;
}
}

@media (max-width:1024px){
.media__thumb {
    width: 60px;
    height: 60px;
    margin-right: 10px !important;
    margin-block-end: 10px;
}

.varient-title-sub {
    align-items: self-end;
    flex-direction: row;
}
.px-wrap {
    text-align: left;
}

.accordion__wrapper {
    text-align: left;
}
}




@media (max-width:767px){

/* 2026-05-12 (Quieter): mobile lens-type tiles + mirror buttons.
   This block used to override the desktop styles with pre-Quieter
   rules (black-solid mirror-active, 2x2 lens-type grid that conflicted
   with the 5-up grid). Now aligned with the Quieter palette:
   - Lens tiles stay as a grid (5 cols at this breakpoint, drops to
     3 cols below 480px via the earlier media rule at line ~340)
   - Mirror buttons inherit the global stacked-mobile layout from the
     ≤640px rule (cream + black border active, NOT solid black)
   - Locked mirror stays hidden via the global selector
   We keep only the truly mobile-specific tweaks (font sizes, lens-
   card detail). */

/* 2026-05-20 Task 6: mobile font bumps for readability */
.lens-card__name { font-size: 15px; }
.lens-card__price { font-size: 14px; }
.lens-card__sub { font-size: 13px; }
.lens-card__desc { font-size: 13px; }
}

/* Footnote link to reveal locked mirror — uses px-size-expand-link class directly */

/* Mirror out-of-stock notice */
.mirror-oos-notice {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    margin-top: 10px;
    padding: 10px 14px;
    background: #f8f4eb;
    border: 1px solid #e8dfc8;
    border-radius: 8px;
    font-size: 12.5px;
    line-height: 1.5;
    color: #5a4e3a;
}
.mirror-oos-notice__icon {
    flex-shrink: 0;
    font-size: 15px;
    line-height: 1.3;
    color: #b8922e;
}
.mirror-oos-notice__text {
    flex: 1;
}
.mirror-oos-notice__text strong {
    font-weight: 600;
    color: #3d3422;
}
.mirror-oos-reveal {
    color: #3b82f6;
    cursor: pointer;
    font-weight: 500;
    margin-top: 4px;
    display: inline-block;
}
.mirror-oos-reveal:hover {
    text-decoration: underline;
}

/* Addon category hint — WCAG AA contrast fix */
.addon-category-hint {
    color: #666 !important;
}

/* Mirror card font — use Space Grotesk for consistency */
.mirror-card h5 {
    font-family: 'Space Grotesk', sans-serif !important;
}
.mirror-card p {
    font-family: 'Space Grotesk', sans-serif !important;
}

/* Model buttons — bigger on mobile: 4 per row */
.px-size-group .px-btn {
    max-width: calc(25% - 6px) !important;
    flex: 0 0 calc(25% - 6px);
    padding: 3px;
}

.px-size-group .px-row {
    gap: 8px;
}

/* Mirror cards — (handled above in stacked layout) */

img.quantity-review-images {
    max-width: 200px;
}

/* Section headings */
.px-block h4, .px-lens h4, .px-wrap h4 {
    font-size: 14px;
    margin: 16px 0 8px;
}
}

.addon-card.disabled {
  opacity: 0.6;
  cursor: not-allowed;
  pointer-events: none;
  position: relative;
}

.addon-card.disabled a,
.addon-card.disabled button {
  pointer-events: none;
}

.addon-card.disabled::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: 110%;
  left: 50%;
  transform: translateX(-50%);
  background: #000;
  color: #fff;
  font-size: 12px;
  padding: 6px 10px;
  border-radius: 4px;
  white-space: nowrap;
  opacity: 0;
  transition: opacity 0.2s ease;
}

/* ============================================================================
   2026-05-14 (mirror-strip above gallery, Option A) — segmented control
   placed above the product gallery on the The View PDP.
   ============================================================================ */
.view-mirror-strip {
  /* 2026-05-14: tight gap to the gallery below (user feedback —
     "remove almost all space above image"). */
  margin: 0 0 4px;
  padding: 0;
  max-width: 100%;
}
/* 2026-05-14: the strip lives in .product__inner (configurator
   column) by default on desktop, and trieye-product.js's
   initMobileLensPosition moves it into .product__media__wrapper on
   mobile so it sits above the gallery. No flex-wrap hacks needed. */
.view-mirror-strip__label {
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: #7a766e;
  font-weight: 600;
  text-align: center;
  margin: 0 0 6px;
}
.view-mirror-strip__seg {
  display: flex;
  background: #f0ece4;
  border-radius: 999px;
  padding: 3px;
}
.view-mirror-strip__btn {
  flex: 1;
  background: transparent;
  border: 0;
  border-radius: 999px;
  padding: 7px 12px;
  font-size: 13px;
  line-height: 1.15;
  cursor: pointer;
  color: #1a1a1a;
  font-family: inherit;
  /* 2026-05-14: transition removed. With a 0.15s transition on
     background, any state change (page restore via applyStored,
     setActiveButton call, etc.) produces an intermediate gray
     mid-flight — user reported "Single mirror is grayed out" after
     switching sides. Removing the transition makes state changes
     instant; no perceived gray. */
}
.view-mirror-strip__btn.is-active {
  /* !important defends against any theme.css button reset or future
     specificity surprise. The active state must always render as the
     primary pill. */
  background: #1a1a1a !important;
  color: #fff !important;
  font-weight: 600 !important;
}
.view-mirror-strip__sports {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 3px;
  margin-top: 4px;
  padding: 0 4px;
  font-size: 10px;
  color: #7a766e;
  text-align: center;
  line-height: 1.3;
  letter-spacing: 0.01em;
}
.view-mirror-strip__footnote {
  font-size: 11px;
  color: #7a766e;
  text-align: center;
  /* 2026-05-14: more air above the footnote so it doesn't crowd
     the Cycling/Rowing sport-hint row. */
  margin: 12px 0 0;
  line-height: 1.4;
  /* Reserve space for the taller of the two states so toggling
     Single ↔ Dual doesn't push later content up/down. ~2 lines of
     11px / 1.4 line-height ≈ 31px. */
  min-height: 32px;
}
.view-mirror-strip__footnote strong {
  color: #333;
  font-weight: 600;
}
.view-mirror-strip__switch {
  color: #1a1a1a;
  text-decoration: underline;
  font-weight: 600;
  cursor: pointer;
}

/* Footnote: swap copy based on active button so total height stays constant
   between Single and Dual states (no layout jump on toggle).
   :has() — Safari 15.4+, Chrome 105+, Firefox 121+. */
.view-mirror-strip__footnote-single,
.view-mirror-strip__footnote-dual {
  display: none;
}
.view-mirror-strip:has(.view-mirror-strip__btn[data-mirror-type="single"].is-active)
  .view-mirror-strip__footnote-single {
  display: inline;
}
.view-mirror-strip:has(.view-mirror-strip__btn[data-mirror-type="dual"].is-active)
  .view-mirror-strip__footnote-dual {
  display: inline;
}

/* Hide the existing mirror .px-block inside the variants snippet on
   products that render the new strip (The View, The Classic, Clip-on).
   Markup is preserved (data attributes carry mirror state for existing
   JS); the strip's click handler forwards to those hidden [data-mirror]
   buttons. Spare Lens unaffected.
   2026-05-15: Clip-on added to match Classic's pattern. */
[data-product-handle="the-view"] .px-block:has(> .px-row.px-mirror-row),
[data-product-handle="the-classic"] .px-block:has(> .px-row.px-mirror-row),
[data-product-handle="clip-on"] .px-block:has([data-mirror]) {
  display: none !important;
}
/* NB: Clip uses `.px-row.px-mirror-row` for BOTH size buttons
   (data-size) and mirror buttons (data-mirror) for visual
   consistency. We only want to hide the MIRROR block, not the size
   block — `:has([data-mirror])` picks out the right one. */

/* Classic + Clip-on also hide the legacy .mirror-footnote and
   .mirror-oos-notice because the strip now owns the side-switch UI.
   (View already removed the markup in the cleanup pass.) */
[data-product-handle="the-classic"] .mirror-footnote,
[data-product-handle="the-classic"] .mirror-oos-notice,
[data-product-handle="clip-on"] .mirror-footnote,
[data-product-handle="clip-on"] .mirror-oos-notice {
  display: none !important;
}
/* 2026-05-14: hide the "Best for ... · Cat 3 · 8-18% VLT · UV400 ·
   Light-transmission bar" panel under CHOOSE YOUR LENS on Classic.
   Customer feedback: it duplicated info already conveyed by the lens
   summary in YOUR BUILD + the lens tile subtitles. Markup kept for
   any JS that may reference the data-lens-detail attribute.
   2026-05-15: Clip-on added for parity (same panel renders on Clip
   when you click a lens — same redundancy with the YOUR BUILD lens
   summary). */
[data-product-handle="the-classic"] .lens-detail,
[data-product-handle="clip-on"] .lens-detail {
  display: none !important;
}

/* 2026-05-15: Clip-on lens-card overrides REMOVED — Clip-on now uses
   the exact same `.lens-card--text` styles as The View, so the lens
   cards look identical across the product family. (Previously this
   block tightened Clip's padding / shrunk the icon / scaled down
   font-sizes; user feedback was that Clip should match View 1:1.)
   The `.px-lens--clip` modifier class on the wrapper is kept in the
   snippet for future product-specific tweaks but currently no CSS
   targets it. */

/* 2026-05-15: Clip-on CHOOSE MODEL — ported from View's pill +
   thumbnail layout. View's default `.px-size-row-flat .px-btn` uses
   `flex: 0 0 calc((100% - 24px) / 4)` (4-per-row), which would shrink
   Clip's 2 buttons to 25% width and leave 50% empty. Override to
   2-per-row at half-width with a generous max so the cards stay
   comfortably proportioned on desktop. Below 480px we fall through to
   the existing 3-per-row rule which naturally accommodates 2 buttons.

   The `[data-product-handle="clip-on"]` prefix bumps specificity to
   (0,3,0) so this rule wins against View's `.px-size-row-flat .px-btn`
   (0,2,0) regardless of source order — both rules sit in the same
   file but View's appears later, and without this prefix the source-
   order tiebreaker would hand the win to View. */
/* 2026-05-21 v2 — Handle was "clip-on" (wrong — current product
   handle is "the-clip", so the old selector matched zero elements
   and the Clip's model picker silently fell through to whatever
   came next). Fixed both selectors plus removed the fixed 110px
   width so Clip matches View / Classic at the same 25% flex basis. */
[data-product-handle="the-clip"] .px-size-row-flat--clip .px-btn {
  flex: 0 0 calc((100% - 24px) / 4);
  min-width: 0;
  max-width: none !important;
  aspect-ratio: 1 / 1;
}

/* 2026-05-15: text label inside the Clip size button. On desktop the
   pill + thumbnail carry the size info, so the label hides. On mobile
   (≤767px) the thumbnail + pill drop out and the label takes over —
   "Medium" / "Small" centered. Cleaner on phone widths where the
   thumbnail repeats the same hero image and the corner pill is a tiny
   single character that adds visual noise. See mobile @media block
   further down for the mobile flip. */
.px-size-row-flat--clip .px-btn__label {
  display: none;
}

/* Clip sizing explainer below the buttons. Surfaces the
   measure-your-own-glasses guidance that's specific to Clip-on (a
   clip-on attaches to existing eyewear, so sizing maps to the
   customer's frame temple width, not face shape). The inline link
   shares the same `data-target-{{ section.id }}` attribute as the
   header Size guide button so it opens the same modal. */
.px-clip-size-help {
  font-size: 12px;
  color: #666;
  line-height: 1.4;
  margin: 10px 0 0;
}
.px-clip-size-help__link {
  background: none;
  border: 0;
  padding: 0;
  margin-left: 2px;
  color: #1a1a1a;
  text-decoration: underline;
  cursor: pointer;
  font: inherit;
}
.px-clip-size-help__link:hover {
  color: #000;
}

/* Single "ONE SIZE" pill in the CHOOSE MODEL legend (Classic). Uses a
   warm tone (#0A6FA8 not great, sticking with the same dark fill as
   M but with a different label to make it obviously one-size). */
.px-title-legend__pill--onesize {
  background: #5b4a32;
}

/* ─── No-dual mode (The Classic) ──────────────────────────────────
   Dual tab is rendered visibly available but with a muted treatment
   so the customer can see it exists. Clicking opens a modal (handled
   in JS) directing them to The View Dual. */
.view-mirror-strip__btn.is-disabled {
  color: #98948c;
  cursor: pointer;
}
.view-mirror-strip__btn.is-disabled:hover {
  color: #7a766e;
}
.view-mirror-strip__btn-tag {
  display: inline-block;
  margin-left: 4px;
  padding: 1px 6px;
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: #fff;
  background: #a86f0a;
  border-radius: 3px;
  vertical-align: middle;
  text-transform: uppercase;
}
/* In no-dual mode the Single button is locked active — remove the
   pointer cursor since clicking it has no effect (it's already
   selected and there's no Dual to swap with). */
.view-mirror-strip--no-dual .view-mirror-strip__btn[data-mirror-type="single"] {
  cursor: default;
}

/* ─── No-dual modal ────────────────────────────────────────────────
   Lightweight modal that appears when a Classic customer clicks the
   disabled Dual tab. Centered overlay with dim backdrop, primary CTA
   to The View Dual + secondary "Stay on Single" button. */
.view-mirror-strip__modal[hidden] {
  display: none;
}
.view-mirror-strip__modal {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}
.view-mirror-strip__modal-overlay {
  position: absolute;
  inset: 0;
  background: rgba(20, 18, 14, 0.55);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}
.view-mirror-strip__modal-content {
  position: relative;
  background: #fff;
  border-radius: 8px;
  padding: 28px 24px 24px;
  max-width: 380px;
  width: 100%;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.25);
  text-align: center;
}
.view-mirror-strip__modal-close {
  position: absolute;
  top: 8px;
  right: 10px;
  width: 32px;
  height: 32px;
  background: transparent;
  border: 0;
  font-size: 22px;
  line-height: 1;
  color: #7a766e;
  cursor: pointer;
  padding: 0;
}
.view-mirror-strip__modal-close:hover {
  color: #1a1a1a;
}
.view-mirror-strip__modal-title {
  margin: 0 0 10px;
  font-size: 17px;
  line-height: 1.3;
  font-weight: 700;
  color: #1a1a1a;
  letter-spacing: 0;
  text-transform: none;
}
.view-mirror-strip__modal-body {
  margin: 0 0 18px;
  font-size: 13px;
  line-height: 1.5;
  color: #555;
}
.view-mirror-strip__modal-cta {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.view-mirror-strip__modal-cta-primary {
  display: block;
  background: #1a1a1a !important;
  /* Override Pipeline's theme anchor styles which set a dark color and
     underline on <a> tags. The CTA is a primary action — keep it
     white-on-black, no underline. */
  color: #fff !important;
  text-decoration: none !important;
  border: 0;
  border-radius: 999px;
  padding: 12px 16px;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.02em;
  text-align: center;
  cursor: pointer;
}
.view-mirror-strip__modal-cta-primary:hover,
.view-mirror-strip__modal-cta-primary:focus {
  background: #000 !important;
  color: #fff !important;
  text-decoration: none !important;
}
.view-mirror-strip__modal-cta-secondary {
  display: block;
  background: transparent;
  color: #444;
  border: 1px solid #d8d4cc;
  border-radius: 999px;
  padding: 10px 16px;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  font-family: inherit;
  text-align: center;
}
.view-mirror-strip__modal-cta-secondary:hover {
  background: #faf7f2;
}

/* Hide the JS-injected mobile model-line on products that render the
   strip (The View, The Classic). The element is created at runtime by
   initMobileLensPosition() in trieye-product.js (line ~1428) and
   inserted between the title and price on mobile (≤767px). The strip
   + active button state + gallery imagery convey the current selection
   without a redundant text summary above the gallery. Clip / Spare
   Lens keep the line. */
[data-product-handle="the-view"] .px-model-line,
[data-product-handle="the-view"] [data-model-line],
[data-product-handle="the-classic"] .px-model-line,
[data-product-handle="the-classic"] [data-model-line] {
  display: none !important;
}

/* Hide elements (color swatches and lens-group buttons) whose underlying
   variant set is incompatible with the current state.mirror. Class applied
   dynamically by trieye-product.js helpers (filterColorSwatchesByMirror,
   filterLensGroupsByMirror). */
.px-btn.is-mirror-incompatible,
.px-group.is-mirror-incompatible {
  display: none !important;
}

/* ============================================================================
   2026-05-14 (V2 size redesign) — single flat row of variants with an
   inline "Small · 140mm" divider between the M and S groups. Mobile:
   horizontal scroll-snap. Desktop: 4-per-row grid (divider becomes a
   full-width band). Replaces V1 segmented toggle.
   ============================================================================ */

/* "CHOOSE MODEL" header row with Size Guide on the right (matches the
   .px-title-row pattern used by CHOOSE YOUR TYPE). */
.sizeguidebtn--inline {
  flex: 0 0 auto;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #444;
  background: #fff;
  border: 1px solid #d8d4cc;
  border-radius: 4px;
  padding: 4px 8px;
  cursor: pointer;
  font-family: inherit;
  line-height: 1.3;
  white-space: nowrap;
}

/* Header-row legend: shows what the M / S pills mean. The pill styling
   mirrors .px-btn__size-pill exactly so the legend reads as "this colour
   pill on a card = this size". */
.px-title-row--with-legend {
  flex-wrap: wrap;
  gap: 6px 12px;
}
.px-title-legend {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  flex: 0 1 auto;
  white-space: nowrap;
}
.px-title-legend__item {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 10px;
  color: #7a766e;
  letter-spacing: 0.02em;
}
.px-title-legend__pill {
  display: inline-block;
  background: #1a1a1a;
  color: #fff;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 1px 5px;
  border-radius: 3px;
  line-height: 1.25;
}
.px-title-legend__pill.is-small {
  background: #a86f0a;
}
.px-title-legend__mm {
  font-weight: 600;
  color: #444;
  letter-spacing: 0.02em;
}

/* Auto-hide the S=140 legend item when no Small variants are rendered in
   the size row below (Small phase-out: when there are no .is-small pills,
   the M=145 legend stands alone, then ultimately the whole legend feels
   redundant and can be removed). */
.px-block.wrap:not(:has(.px-btn__size-pill.is-small)) .px-title-legend__item--small {
  display: none;
}

/* Hide legacy size sub-section labels + expand link when V2 flat row is on.
   The legacy .px-color-medium and .px-color-small wraps stay in DOM
   (existing JS reads them), they just flow into the flat row layout. */
[data-v2-flat-size] > .px-size-info-row,
[data-v2-flat-size] > .px-size-expand-link,
[data-v2-flat-size] .px-size-section-small > .px-size-info {
  display: none !important;
}
[data-v2-flat-size] .px-size-section-small {
  /* Reset the legacy collapsed-by-default Small section so its swatches
     flow into the flat row regardless of the .is-open class. */
  display: contents !important;
}

/* V2-C: wrap-friendly flex row. Cards shrink, wrap on overflow, center
   when there are few. .px-color-medium / .px-color-small / .px-size-group
   are display:contents so their .px-btn children flow into this row. */
.px-size-row-flat {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  /* 2026-05-15 (revised): user feedback — CHOOSE MODEL thumbnails
     should be LEFT-aligned across all products. Centering felt
     visually awkward when only 1-2 thumbnails rendered. Back to
     `flex-start`. */
  justify-content: flex-start;
  align-items: stretch;
  margin-top: 4px;
  /* 2026-05-15 (anti-jump #2): reserve vertical space for the model
     thumbnails BEFORE the swatch-builder JS populates them. Without
     this, the row is 0px tall at first paint, then snaps to ~140px
     when renderGroupedColors() injects buttons after page load —
     pushing everything below (YOUR BUILD, addons, etc.) down by
     136px (measured via position-sampling on View desktop). 144px
     = 140px thumbnail + 4px gap-headroom; the buttons are square at
     max-width 140 with aspect-ratio 1:1.
     On Clip the thumbnails are STATIC Liquid (not JS-injected), so
     this reservation is a harmless no-op there — the static
     buttons already determine the height.
     Mobile: thumbnails switch to text-only ~52px buttons; we
     override below. */
  min-height: 144px;
}
@media (max-width: 480px) {
  .px-size-row-flat {
    /* Mobile thumbnails are smaller (3-per-row at ~78px on View),
       and on Clip they switch to text-only labels (~52px). Reserve
       enough for whichever appears. */
    min-height: 88px;
  }
}
.px-size-row-flat > .px-size-group,
.px-size-row-flat .px-size-section-small,
.px-size-row-flat .px-size-section-small > .px-size-group,
.px-size-row-flat .px-size-group > .px-color-medium,
.px-size-row-flat .px-size-group > .px-color-small {
  display: contents;
}
.px-size-row-flat .px-btn {
  flex: 0 0 calc((100% - 24px) / 4);  /* 4-per-row default with 3 × 8px gaps */
  min-width: 84px;
  /* 2026-05-21 v2 — Was 140 → 110 → none. The 110 cap was wrong:
     Classic renders intrinsically at ~25% of its column (~270px on
     a wide PDP) because its rule `.px-size-group .px-btn` uses
     `max-width: calc(25% - 6px) !important`. To match Classic's
     size we just need to LET View/Clip flex to the same 25% basis
     instead of capping smaller. `none` removes the artificial cap;
     `flex: 0 0 calc((100% - 24px) / 4)` already targets 25%. */
  max-width: none !important;
  position: relative;
  aspect-ratio: 1 / 1;
}
@media (max-width: 480px) {
  .px-size-row-flat .px-btn {
    flex: 0 0 calc((100% - 16px) / 3);  /* 3-per-row on narrow mobile */
    min-width: 78px;
    max-width: none !important;
  }
  /* 2026-05-15: Clip override for the mobile rule above. View's mobile
     rule freezes buttons at 3-per-row (78px) which leaves Clip's 2
     buttons hugging the left edge with ~115px of empty space on the
     right. Flex Clip's pair back to 1 1 0 so they grow to fill the
     row evenly, with a generous min so the thumbnails stay legible.
     Uses the same `[data-product-handle="clip-on"]` specificity bump
     as the desktop rule so both rules win consistently. */
  /* 2026-05-21 v2 — Handle was "clip-on" → fixed to "the-clip" */
  [data-product-handle="the-clip"] .px-size-row-flat--clip .px-btn {
    flex: 1 1 0;
    min-width: 100px;
    max-width: none !important;
  }
}

/* 2026-05-15: mobile = text-only buttons.
   ─────────────────────────────────────────────────────────────────
   USER FEEDBACK: on mobile, the SVG lens icons and the size-button
   thumbnails feel cluttered — the screen is already narrow, and the
   text alone (lens name, "Medium" / "Small") carries the information.
   Mobile breakpoint is 767px (matches the rest of the responsive
   system in this theme).

   What changes at ≤767px:
   - `.lens-card__icon` (all configurators) → hidden. Text remains
     centered via the existing `.lens-card { align-items: center;
     text-align: center; }` baseline.
   - Clip size-button `.px-img` + `.px-btn__size-pill` → hidden.
     `.px-btn__label` ("Medium" / "Small") becomes visible, centered
     in the button via flex.
   - Button `aspect-ratio: 1/1` is removed so the text-only buttons
     don't force tall empty space.
*/
@media (max-width: 767px) {
  .lens-card__icon {
    display: none !important;
  }
  /* 2026-05-21 — Reverted the 2026-05-15 text-only mobile pivot.
     User feedback: the thumbnail + corner pill DO carry the size
     info clearly, and the rectangular text-only buttons broke
     consistency with The View / Classic (which stay square at
     all breakpoints). Keep the image + pill visible, lock to
     1/1, hide the redundant text label. */
  .px-size-row-flat--clip .px-img,
  .px-size-row-flat--clip .px-btn__size-pill {
    display: block; /* visible at all breakpoints */
  }
  .px-size-row-flat--clip .px-btn {
    aspect-ratio: 1 / 1;
  }
  .px-size-row-flat--clip .px-btn__label {
    display: none; /* image + corner pill carry the size info */
  }
}

/* Per-card size pill (top-right corner). Black for M (default), amber for
   S — a quiet visual cue while Small is being phased out. When Small is
   removed entirely, the .is-small variant simply won't render and the
   black M pill on every card looks consistent. */
.px-btn__size-pill {
  position: absolute;
  top: 4px;
  right: 4px;
  background: #1a1a1a;
  color: #fff;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 1px 5px;
  border-radius: 3px;
  line-height: 1.25;
  z-index: 2;
  pointer-events: none;
}
.px-btn__size-pill.is-small {
  background: #a86f0a;
}
.px-btn--sold-out .px-btn__size-pill {
  opacity: 0.55;
}

/* Welcome-back toast (rendered/destroyed by JS in trieye-product.js) */
.trieye-config-toast {
  background: #fff8e6;
  border: 1px solid #e7d293;
  padding: 8px 11px;
  border-radius: 6px;
  font-size: 12px;
  line-height: 1.35;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  margin: 0 0 10px;
}
.trieye-config-toast a.apply {
  color: #111;
  text-decoration: underline;
  font-weight: 600;
  white-space: nowrap;
  cursor: pointer;
}
.trieye-config-toast .close {
  color: #999;
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
}

.addon-card.disabled:hover::after {
  opacity: 1;
}

/* ============================================================================
   2026-05-14 (mirror-strip refinement) — lens-card text-only + inline header
   ============================================================================ */

/* Lens-card text variant. Originally introduced as no-icon for V2-C
   compactness; 2026-05-15 the icon was restored on user request — it's
   the consistent visual cue across Classic/Clip/Spare Lens. The icon
   sits at 20px (smaller than Classic's 22px default) to stay inside
   the tight 5-up button width without forcing the H5 to wrap. */
.lens-card--text {
  display: flex;
  flex-direction: column;
  align-items: center;        /* center children horizontally */
  justify-content: center;    /* center content vertically inside the button */
  text-align: center;
  /* 2026-05-21 — Per user: padding 10×4 (was 6×0). The 4px side
     padding adds a small inset from the surrounding `.px-group`
     padding (now 2px); 10px top/bottom gives the icon/title stack
     more vertical breathing room. */
  padding: 10px 4px;
  gap: 2px;
  width: 100%;
  min-height: 52px;           /* uniform button height across the row */
}
.lens-card--text .lens-card__icon {
  /* Icon container — fixed compact size so the row above the H5 is a
     consistent height across all 5 lens tiles even when the SVG art
     varies slightly. `color: currentColor` lets the active state
     (cream/black inherited from .px-group.active) tint the stroke. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  margin-bottom: 2px;
  color: #1a1a1a;
}
.lens-card--text .lens-card__icon svg.px-lens-icon {
  width: 20px;
  height: 20px;
  display: block;
}
.px-group.active .lens-card--text .lens-card__icon { color: #111; }
.lens-card--text .lens-card__name {
  font-size: 13px;
  font-weight: 700;
  margin: 0;
  line-height: 1.15;
  letter-spacing: 0.01em;
  /* 2026-05-15: `width: 100%` forces the H5 to take the full card
     content width even though .lens-card--text uses
     `align-items: center` (which would otherwise shrink the H5 to
     its content size). Without this, the H5 was 72px even though
     the card content area was 86px — leaving "Photochromic" (86px
     scrollW) overflowing into ellipsis. */
  width: 100%;
}
.lens-card--text .lens-card__sub {
  font-size: 10px;
  color: #888;
  line-height: 1.25;
  letter-spacing: 0.01em;
}
.lens-card--text .lens-card__price {
  font-size: 11px;
  color: #555;
  margin-top: 2px;
}
.px-group:has(.lens-card--text) {
  /* tighter padding since no SVG icon takes vertical space */
  min-height: auto;
}
.px-group.active .lens-card--text .lens-card__sub { color: #555; }

/* Inline current-lens label appended to "CHOOSE YOUR TYPE" h4 */
.px-title__current {
  font-weight: 400;
  color: #7a766e;
  letter-spacing: 0.02em;
  text-transform: none;
  font-size: 0.95em;
  margin-left: 0;
}
.px-title__current:empty { display: none; }

/* H4 row: title on left, UV/VLT spec chips on right, same baseline */
.px-title-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 8px;
  flex-wrap: wrap;
}
.px-title-row .px-title {
  margin: 0;
  flex: 1 1 auto;
  min-width: 0;
}
.px-title-specs {
  display: flex;
  gap: 4px;
  align-items: baseline;
  flex: 0 0 auto;
}
.px-title-spec {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #444;
  background: #f0ece4;
  border: 1px solid #e8e5dd;
  border-radius: 4px;
  padding: 2px 6px;
  white-space: nowrap;
  line-height: 1.3;
}
.px-title-spec--vlt:empty {
  display: none;
}

/* Name + sub wrap freely so longer labels ("High Contrast",
   "Photochromic") never need ellipsising. `white-space: normal` is
   REQUIRED — without it, text would inherit `nowrap` from the
   <button> reset rule (`button { white-space: nowrap }`), which then
   can't wrap regardless of width.
   2026-05-15: ellipsis + `-webkit-line-clamp` previously here were
   removed at user request; truncation now relies entirely on
   `.px-groups > .px-group { min-width: 90px }` giving every tile
   enough width for "Photochromic" (~86px @ 13px), with
   `flex-wrap: wrap` on `.px-groups` as the last-resort overflow
   fallback (pushes a tile to a second row, never clips text). */
.lens-card--text .lens-card__name {
  white-space: normal;
  max-width: 100%;
  line-height: 1.15;
}
.lens-card--text .lens-card__sub {
  white-space: normal;
  max-width: 100%;
  line-height: 1.25;
}

/* ════════════════════════════════════════════════════════════════════
   2026-05-21 v3 — FINAL OVERRIDE: identical model-picker button size
   across View / Classic / Clip at every breakpoint.

   Background: multiple earlier rules in this file set conflicting
   widths on `.px-size-group .px-btn` (Classic), `.px-size-row-flat
   .px-btn` (View), and `.px-size-row-flat--clip .px-btn` (Clip):
     Classic desktop  →  max-width: calc(25% - 6px) !important
     View desktop     →  flex: 0 0 calc(25%); max-width: 140/110/none
     View mobile      →  flex: 0 0 calc(33.33%)            ← bigger
     Clip desktop     →  flex: 0 0 140px (fixed)            ← smaller
     Clip mobile      →  flex: 1 1 0 (grow to fill)         ← much bigger
   Net effect: buttons rendered at three different widths depending
   on which configurator you opened.

   This block (placed last so source order is on its side) collapses
   all of the above into one truth: every model-picker button is 25%
   of its parent row width, with 1:1 aspect-ratio, regardless of
   wrapper class. Result is identical button geometry across all
   three configurators on any viewport.

   Why 25%: that's Classic's intrinsic rule and the user calls it
   "correct size." With only 1-2 buttons in View / Classic / Clip,
   the row has whitespace to the right — but each BUTTON is identical,
   which is what was asked for.
   ════════════════════════════════════════════════════════════════════ */
.px-size-group .px-btn,
.px-size-row-flat .px-btn,
.px-size-row-flat--clip .px-btn {
  flex: 0 0 calc(25% - 6px) !important;
  width: auto !important;
  max-width: calc(25% - 6px) !important;
  min-width: 0 !important;
  aspect-ratio: 1 / 1 !important;
}

@media (max-width: 480px) {
  .px-size-group .px-btn,
  .px-size-row-flat .px-btn,
  .px-size-row-flat--clip .px-btn,
  [data-product-handle="the-clip"] .px-size-row-flat--clip .px-btn,
  [data-product-handle="the-view"] .px-size-row-flat .px-btn {
    flex: 0 0 calc(25% - 6px) !important;
    max-width: calc(25% - 6px) !important;
    min-width: 0 !important;
    aspect-ratio: 1 / 1 !important;
  }
}

/* ════════════════════════════════════════════════════════════════════
   2026-05-21 — CHOOSE YOUR LENS card width consistency.

   Problem: `.px-groups > .px-group { flex: 1 1 0 }` made each lens
   tile grow to fill the row. With 5 tiles (View) each was ~20% wide;
   with 4 (Classic) each was ~25%; with 2 (Clip) each was ~50%. The
   tiles felt different sizes across products — user feedback:
   "the classic choose your lens is not showing good."

   Mobile had the same problem in the grid form — View used 3-col
   (cards 33%), Classic 4-col (25%), Clip 2-col (50%).

   Fix: ALL .px-group lens tiles render at the SAME width regardless
   of how many tiles exist in the row. Desktop = 140px fixed (matches
   View's intrinsic 5-up width on a typical PDP column). Mobile = 3-col
   grid for every product, so the per-card width is identical across
   View/Classic/Clip; rows with fewer than 3 cards just leave the last
   columns empty.
   ════════════════════════════════════════════════════════════════════ */
/* 2026-05-21 v5 — Lens-picker layout:
   • Desktop (≥768px): ALL lens tiles on one row (per user). View's 5,
     Classic's 4, Clip's 2 all flow into a single row regardless of
     count. `grid-auto-flow: column` + `grid-auto-columns: 1fr` makes
     every child take equal share of the row.
   • Mobile (≤767px): 2 × 2 grid (A1 layout) so long names like
     "Photochromic" stay on one line at 14px font.
   Row-gap stays at 18px on mobile so the Photochromic BESTSELLER
   badge (top: -10px) clears the card in the row above it. */
.px-groups {
  display: grid !important;
  grid-auto-flow: column !important;
  grid-template-columns: unset !important;
  grid-auto-columns: 1fr !important;
  gap: 10px !important;
  justify-content: stretch !important;
}
.px-groups > .px-group {
  flex: initial !important;
  max-width: none !important;
  min-width: 0 !important;
  width: auto !important;
  /* 2026-05-21 — Per user: tightened from 14×10 to 2px all around so
     the lens-card content gets maximum room inside each tile. */
  padding: 2px !important;
}

@media (max-width: 767px) {
  /* Mobile lens-picker grid — capped at 2 rows total per user
     direction. Column count adapts to tile count:
       2 tiles (Clip)    → 2 cols → 1 row (2)
       4 tiles (Classic) → 2 cols → 2 rows (2 + 2)
       5 tiles (View)    → 3 cols → 2 rows (3 + 2)
     Long names like "Photochromic" still fit at 14px with no break
     because even 3-col mobile gives ~95px content per card. */
  .px-groups {
    grid-auto-flow: row !important;
    grid-template-columns: repeat(2, 1fr) !important;   /* default = 2 col */
    grid-auto-columns: unset !important;
    gap: 18px 8px !important;        /* row-gap 18px → badge clears */
  }
  /* 5-tile picker (View) gets a 3-col grid so it wraps to 3 + 2 */
  .px-groups:has(> .px-group:nth-child(5)) {
    grid-template-columns: repeat(3, 1fr) !important;
  }
  /* 2026-05-21 — User direction: bump mobile lens-tile padding 2 → 11 so
     the lens-card content gets a bit more breathing room from the tile
     edge on phones (the earlier 2px was visually too tight against
     the cream active-state background). */
  .px-lens .px-groups > .px-group,
  .px-lens--clip .px-groups > .px-group,
  .px-lens--swatches .px-groups > .px-group,
  .px-lens--swatches .px-groups button.px-group {
    padding: 11px !important;
  }
}

/* ════════════════════════════════════════════════════════════════════
   2026-05-21 — CHOOSE YOUR LENS visual: follow The Classic.

   The Classic renders the lens-icon snippet but returns empty content
   for its lens labels (the per-product metafield mapping doesn't hit
   for "Polarized Brown" etc.), so its lens-cards display text-only.
   View + Clip have populated icons in the SVG snippet, so they
   show ⊕ / half-moon / target / etc. above each name. User
   feedback: "should follow the classic. both clip and view" —
   strip the icons so all three configurators read as identical
   text-only cards.
   ════════════════════════════════════════════════════════════════════ */
[data-product-handle="the-view"] .lens-card__icon,
[data-product-handle="the-clip"] .lens-card__icon,
.px-lens--clip .lens-card__icon {
  display: none !important;
}

/* 2026-05-21 — Hide redundant REAR-VIEW MIRROR POSITION block on Clip.
   The top view-mirror-strip already covers Single/Dual + side-switch
   via its data-mirror-side link. The lower block (h4 + .px-mirror-row
   + .mirror-footnote) was duplicating the choice and confused users.
   We keep the markup in DOM so the existing JS selectors continue to
   resolve (the top strip forwards clicks to [data-mirror] buttons in
   this hidden block). */
[data-product-handle="the-clip"] .px-block:has(> .px-row.px-mirror-row),
[data-product-handle="clip-on"]  .px-block:has(> .px-row.px-mirror-row) {
  display: none !important;
}