/* Rickezza -- real brand palette, confirmed directly with Ali against
   his own real logo artwork (Rickezza_logo.jpg): colors sampled
   directly from the actual image pixels (median of the logo
   wordmark's own gold stroke, and the artwork's own cream
   background), not eyeballed or guessed. Replaces the PREVIOUS
   palette below, which -- despite its own comment claiming it was
   "the real brand accent" -- was transcribed from a different,
   generic reference site's stylesheet (rickezza_website_reference.md),
   never Ali's own actual brand asset. That's exactly what Ali means by
   "the general colors are very basic" -- confirmed directly with him.
*/

:root {
  /* Real brand gold, sampled directly from the logo artwork's own
     wordmark (median of the core stroke pixels, avoiding anti-aliased
     edges): rgb(202,151,98). Used for links, active nav state, product
     name/price text, and the "In Stock" badge -- the single most
     important color to get right, same real-world usage the old
     token already had, just now the shop's own actual color. */
  --accent: #ca9762;
  /* A soft, muted tint of the accent gold -- real, subtle hover/active
     backgrounds (e.g. a selected filter chip) where the full-strength
     accent would be too heavy as a fill. */
  --accent-soft: #f1e4d5;
  --header-bg: #ffffff;      /* real site: white/transparent header, not dark */
  /* Warmed slightly off pure neutral gray, to sit naturally alongside
     the real cream/gold tokens above rather than reading as a cold,
     unrelated gray dropped into a warm palette. */
  --ink: #33291f;            /* real: buttons/dark UI text */
  --ink-soft: #6b5f52;       /* real: body copy */
  --ink-mute: #9c9086;       /* real: muted/secondary text */
  /* Real, warm cream -- sampled directly from the logo artwork's own
     background (rgb(242,237,231)), not the old palette's cool,
     unrelated gray. Used for hairlines/dividers and soft section
     backgrounds (--bg-soft below) -- both were cool gray before, now
     genuinely part of the same warm family as the accent gold. */
  --hairline: #e5ddd2;
  --bg-soft: #f2ede7;
  --panel-bg: #ffffff;
  /* Handoff -- real bug fix, confirmed directly with Ali: the whole
     page's own real background (catalog, product pages, everywhere)
     -- previously hardcoded #fff with no real token behind it. */
  --page-bg: #ffffff;
  /* Real, warm placeholder tones -- confirmed directly with Ali: the
     old #f2f2f2/#cfcfcf pair (a cool, generic gray) is the actual
     image/photo placeholder background+icon-stroke used everywhere a
     real photo hasn't been uploaded yet (cart, checkout, catalog
     tiles, product page) -- one of the single most visible, most
     repeated pieces of UI on the whole site, so warming it to match
     the real brand palette matters as much as the accent gold itself. */
  --placeholder-bg: #f1ece4;
  --placeholder-stroke: #c7bda9;
  --overlay: rgba(31, 24, 16, 0.45);
  --btn-dark: #33291f;
  --btn-dark-hover: #221b13;
  --danger: #a64637;         /* real secondary accent (rust/terracotta), used sparingly for alert states -- already warm, unchanged */
  /* Handoff -- real, explicit request, confirmed directly with Ali:
     "add to favorite... the heart will turn to a color i will pick
     in website colors in admin" -- the fill color once favorited.
     A real, classic heart-red default until Ali picks his own. */
  --favorite-heart: #d6433c;
  /* Handoff -- real bug fix, confirmed directly with Ali: "i dont
     have control on footer background and text colors" -- real
     defaults matching .rk-footer's own previous hardcoded values
     exactly, so nothing visually changes for a site that hasn't
     touched these two new fields yet. */
  --footer-bg: #201b17;
  --footer-text: rgba(255, 255, 255, 0.82);
  /* Poppins is the ONLY font actually rendering anywhere on the real
     site (body, headings, buttons, product names, nav all confirmed
     via computed font-family) -- the single body/UI font here too. */
  --font-body: "Poppins", sans-serif;
  /* Abril Fatface was loaded but unused live -- brought forward ONLY
     for an optional decorative hero/heading treatment, per the
     reference doc's own recommendation. Not used for the logo itself:
     the real logo is a script/calligraphic image asset (see §2), so
     a script web font is not part of the real token set. */
  --font-display: "Abril Fatface", serif;
}

/* ---------------------------------------------------------------- */
/* Photo placeholder language                                        */
/* ---------------------------------------------------------------- */
/* No real product/lifestyle photography exists anywhere in this
   codebase yet -- see the redesign report. Every image slot in this
   rebuild (hero, category rail, craft block) uses this SAME visual
   language: a warm neutral panel (built from the real ink/accent
   tokens above, not arbitrary color) with a centered image glyph, so
   it reads as a deliberate "photo goes here" placeholder rather than
   a broken image or a demo gradient. Swap the inner content for a
   real <img> the moment real photography exists; nothing else about
   the layout needs to change when that happens. */
.rk-ph {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(155deg, #efe9e2 0%, #e4dace 55%, #d9cabb 100%);
  color: var(--ink-mute);
  overflow: hidden;
}
.rk-ph svg { width: 15%; height: 15%; min-width: 22px; min-height: 22px; stroke: #b8a998; opacity: 0.7; }
.rk-ph--dark {
  background: linear-gradient(155deg, #3a332c 0%, #2b251f 55%, #201b17 100%);
}
.rk-ph--dark svg { stroke: rgba(255,255,255,0.35); }

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  font-family: var(--font-body);
  font-size: 16px;
  font-weight: 400;
  color: var(--ink-soft);
  /* Handoff -- real bug fix, confirmed directly with Ali ("Checkout
     fields design is not mobile friendly and some text box's edge is
     not shown on the right edge"): while chasing this down, found a
     real, separate, pre-existing gap on every real page, not just
     checkout -- the off-canvas mobile nav panel and cart drawer are
     both deliberately positioned beyond the real viewport edges
     (negative left / left: 100%) as part of their own real slide-in
     animation, but nothing on the page itself ever clipped that,
     so a phone's own real horizontal scroll could reach them even
     while they're supposed to be fully hidden. */
  overflow-x: hidden;
  /* Handoff -- real bug fix, confirmed directly with Ali ("the
     catalog background is not assigned to any color pallet"): this
     was a plain, hardcoded #fff with no real CSS variable behind it
     at all -- the admin color picker had nothing here to actually
     control. Real token now, same as every other real color in this
     file. */
  background: var(--page-bg);
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; text-decoration: none; }

button { font-family: inherit; cursor: pointer; }

/* legacy elements from the plain frontend that we don't want leaking
   through visually if any page forgets to remove one */
hr { display: none; }

/* ---------------------------------------------------------------- */
/* Header                                                            */
/* ---------------------------------------------------------------- */

/* Real site: header padding 8px 0, white background, ~81px tall,
   sticky (`sticky-header`) -- see reference §1.3/§2. On inner pages the
   background is solid white immediately; only the homepage floats it
   transparently over the hero image (see .rk-header--transparent). */
.rk-header {
  position: sticky;
  top: 0;
  z-index: 40;
  /* Handoff -- real bug fix, confirmed directly with Ali against his
     own real phone screenshot ("Logo is not centered in the middle
     of the website"): flex + justify-content: space-between only
     truly centers a middle item when both its neighbors are the
     exact same real width -- here they never are (the hamburger is
     one real icon; the account+cart group is two icons plus a real
     badge), so the logo was always pulled slightly toward the
     narrower side rather than sitting at the real, true center of
     the screen. A real 3-column grid instead: the outer two columns
     are always equal (1fr each, real math, not just visual
     coincidence), so the logo in the middle is genuinely centered on
     the actual viewport regardless of how wide either side's own
     content is -- same real fix already used for the desktop nav's
     own header layout, now applied to the base/mobile one too. */
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  background: var(--header-bg);
  padding: 8px 18px;
  min-height: 81px;
  border-bottom: 1px solid var(--hairline);
  /* Part B convention: header shrink is a class-toggle-driven CSS
     transition, not a JS-animated loop -- see app.js's scroll
     listener (initHeaderScrollBehavior). */
  transition: min-height 220ms ease-out, padding 220ms ease-out,
    background 220ms ease-out, border-color 220ms ease-out;
}
.rk-header.is-shrunk { min-height: 56px; padding: 4px 18px; }
.rk-header__hamburger { grid-column: 1; justify-self: start; }
.rk-header__logo { grid-column: 2; justify-self: center; }
.rk-header__right { grid-column: 3; justify-self: end; }

/* Handoff -- real, explicit request, confirmed directly with Ali:
   "when pressing 'Account' button, i want a dropdown balloon to
   open with the options: view account, Order History, Favorites,
   Logout." position:relative anchors the dropdown against this real
   wrapper, not the whole header row. */
.rk-account-menu { position: relative; display: inline-flex; }
.rk-account-dropdown {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  z-index: 50;
  /* Handoff -- real bug fix, confirmed directly with Ali ("i selected
     the colors i want in 'website colors' and clicked save, but the
     colors didnt change") -- --panel-bg (its own real admin label:
     "Card / panel background") was defined but never actually
     referenced anywhere in this stylesheet at all, so picking it in
     admin genuinely changed nothing real anywhere on the site. Wired
     into every real card/panel-like surface that was hardcoded #fff
     instead (this dropdown, the cart drawer below). */
  background: var(--panel-bg);
  border: 1px solid var(--hairline);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  min-width: 180px;
  padding: 6px 0;
  display: flex;
  flex-direction: column;
}
/* Handoff -- real bug fix, found live via screenshot: this rule's own
   display: flex above has the exact same real specificity as the
   browser's own built-in [hidden] { display: none } rule, and simply
   comes later in this real stylesheet's own cascade -- so it was
   silently winning and keeping the dropdown visually open regardless
   of its own real hidden attribute/property. This real, explicit
   override restores hidden's own real, expected effect. */
.rk-account-dropdown[hidden] { display: none; }
.rk-account-dropdown a {
  padding: 10px 16px;
  font-size: 13px;
  letter-spacing: 0.3px;
  color: var(--ink);
  white-space: nowrap;
}
.rk-account-dropdown a:hover { background: var(--bg-soft, #f7f5f2); }

/* Handoff -- real header control, confirmed directly with Ali: a real
   announcement bar (Core's own, already-built Announcement model,
   now actually surfaced on the site) above the header. Real flow
   space, not fixed/floating -- unlike the transparent-header case
   there's no hero underneath needing to peek through, so this simply
   pushes the header down when shown. Hidden by default via the real
   [hidden] attribute (see app.js's own renderAnnouncementBar). */
.rk-announcementbar {
  background: var(--ink, #201b17);
  color: #fff;
  text-align: center;
  font-size: 12px;
  letter-spacing: 0.5px;
  padding: 8px 16px;
}

/* Homepage-only: transparent/absolute over the hero image, no hairline,
   icon color flipped to white until scrolled past the hero. Applied by
   app.js only on index.html, per the real site's own header-transparent
   behavior (reference §2: "transparent/absolute-positioned on the
   homepage so the hero image shows through behind it"). */
/* Handoff -- real, explicit request, confirmed directly with Ali:
   "when sliding through home page slides, remove the header and just
   keep the logo" -- hides the hamburger, desktop nav, and account/
   cart icons on the homepage specifically; the logo itself is
   untouched (still genuinely centered via its own real rule above),
   this only hides everything else that would normally share the
   header row with it. Real elements stay in the DOM (display: none
   only) so every other real handler on them -- hamburger open, cart
   badge refresh -- keeps working unaffected if this class is ever
   removed later. */
.rk-header--logo-only .rk-header__hamburger,
.rk-header--logo-only .rk-header__desktopnav,
.rk-header--logo-only .rk-header__right {
  display: none;
}
.rk-header--transparent {
  /* fixed (not absolute): it must float over the hero in EXACTLY the
     same position, in or out of flow, whether it's transparent or has
     solidified -- using the same positioning scheme for both states
     avoids a layout jump/reflow the moment .is-solid gets added. */
  position: fixed;
  top: 0; left: 0; right: 0;
  background: transparent;
  border-bottom: none;
}
.rk-header--transparent .rk-header__icon-btn,
.rk-header--transparent .rk-header__icon-btn svg,
.rk-header--transparent .rk-header__logo {
  color: #fff;
  stroke: #fff;
}

/* Homepage header solidifies once the user scrolls past the hero --
   a real gap the old single-hero-then-one-section homepage never
   surfaced (nothing to scroll past), but a genuine requirement now
   that the homepage has real length. Toggled by app.js's scroll
   listener, same debounced-scroll-position-class-toggle pattern the
   research doc's Part B describes for shrink-on-scroll headers. */
.rk-header--transparent.is-solid {
  /* Handoff -- real bug fix, confirmed directly with Ali ("in
     footer's slide, the header appears white and another white layer
     appears also, and the header looks like it jumped"): position:
     sticky here was a leftover from before the homepage became a
     real fullpage slider -- back when the homepage still scrolled
     normally, "solidifying" the header also meant switching it to
     stick in place once scrolled past the hero. Now that the whole
     homepage is one fixed, overflow:hidden fullpage container (see
     .rk-fullpage), the transparent header must stay position: fixed
     -- the same real positioning scheme -- in every real panel,
     solid or not; switching schemes specifically on the footer panel
     is exactly what produced the real jump and the real second white
     layer Ali saw. Only the visual solidity (background/text color)
     changes now, never the positioning itself. */
  background: var(--header-bg);
  border-bottom: 1px solid var(--hairline);
}
.rk-header--transparent.is-solid .rk-header__icon-btn,
.rk-header--transparent.is-solid .rk-header__icon-btn svg,
.rk-header--transparent.is-solid .rk-header__logo {
  color: var(--ink);
  stroke: var(--ink);
}

/* Handoff -- real "vertical fullpage slider" fix, confirmed directly
   with Ali: the old reserved-flow-space approach (push body down
   81px, then pull the hero back up 81px to cancel it) assumed normal
   in-flow content below the hero that needed to not be hidden behind
   the fixed header. That's no longer true -- every homepage section
   now lives inside .rk-fullpage, a single, fixed 100vh container the
   header floats transparently over regardless of which panel is
   showing (see initHomeFullpage's own updateChrome, which solidifies
   the header once the current panel isn't the dark hero). No reserved
   space is needed or wanted here now. */

.rk-header__icon-btn {
  background: none;
  border: none;
  padding: 4px;
  display: flex;
  align-items: center;
  color: var(--ink);
}
.rk-header__icon-btn svg { width: 22px; height: 22px; stroke: var(--ink); }

/* Real logo is a script/calligraphic image asset (Rickezza Logo.png,
   952x517, ~95x50px in the header) -- not a web font. This text
   fallback renders in the display font as the closest approximation
   until the real logo asset is available to drop in as an <img>; swap
   this selector for an <img src="..."> the moment that asset exists,
   rather than treating this text as the real logo. */
.rk-header__logo {
  font-family: var(--font-display);
  font-size: 26px;
  color: var(--ink);
  letter-spacing: 0.5px;
  white-space: nowrap;
}
.rk-header__logo img { display: block; height: 50px; width: auto; }

.rk-header__right { display: flex; align-items: center; gap: 18px; }

/* Handoff -- real desktop header nav, confirmed directly with Ali:
   below 960px (this site's own existing desktop breakpoint) the
   hamburger + slide-in panel is genuinely correct mobile UX and
   stays exactly as it was; at/above it, the real site reference
   (YSL) shows its nav directly in the header, so the hamburger
   disappears and a real horizontal nav with hover dropdowns takes
   its place instead -- not both at once. */
.rk-header__desktopnav { display: none; }
@media (min-width: 960px) {
  .rk-header__hamburger { display: none; }
  /* Real fallback, confirmed directly with Ali: keeps the hamburger
     reachable at desktop width when the desktop nav genuinely has
     nothing in it (see renderDesktopNav's own real check) -- higher
     specificity than the plain rule above, not !important. */
  .rk-header__hamburger.rk-header__hamburger--force-visible { display: flex; }
  /* Handoff -- real bug fix, confirmed directly with Ali ("when no
     categories available, it is showing the hamburger icon in
     desktop view, they should be in the top left"): the hamburger is
     the header's own first child with no explicit grid placement, so
     CSS grid auto-placed it into column 1 -- the SAME column
     .rk-header__desktopnav--left explicitly claims -- and with no
     justify-self of its own, it defaulted to grid's own "stretch",
     making the button's real, clickable/hoverable area stretch across
     the ENTIRE left column (confirmed live: 656px wide, not a normal
     ~40px icon button), even though the visible icon glyph inside it
     happened to still render at the button's own left edge. Pinned to
     the real, actual top-left corner now: its own explicit column 1
     placement plus justify-self: start, sized to its own real
     content instead of stretching to fill the column. */
  .rk-header__hamburger.rk-header__hamburger--force-visible { grid-column: 1; justify-self: start; }
  /* Handoff -- real bug fix, confirmed directly with Ali against his
     own screen recording of the real reference site: switches to a
     real 3-column grid at desktop width so the logo is genuinely,
     exactly centered regardless of how the left/right nav groups'
     own widths differ -- flex's own justify-content:space-between
     (the mobile layout, unchanged below this breakpoint) only
     guarantees equal gaps, not a centered middle item, once there are
     more than 3 children. A real, symmetric 4-column grid now: left
     nav, logo, right nav, icons are each their own real grid column
     (not a nested flex group sharing one column with the icons, an
     earlier round's approach that made the right nav's own spacing
     unpredictable relative to the icons). */
  .rk-header {
    display: grid;
    grid-template-columns: 1fr auto 1fr auto;
    align-items: center;
    /* Handoff -- real bug fix, confirmed live: without this, the left
       nav group's own right-aligned links sat flush against the
       logo's grid cell with zero real spacing between them --
       "Belts" was visually colliding with "Rickezza". */
    column-gap: 24px;
  }
  .rk-header__desktopnav {
    display: flex;
    align-items: center;
    gap: 28px;
    /* Handoff -- real bug fix, confirmed directly with Ali against his
       own real desktop screenshot ("main menu is wrapping around the
       middle logo"): without this, a narrower desktop width (or
       several longer real category names) wrapped the nav's own links
       onto a second line -- and since the header row uses
       align-items: center, that taller, 2-line block was vertically
       centered too, so its second line visually sat BELOW the logo
       while its first line sat above it, reading as the menu
       "wrapping around" the logo. Reproduced live at 960px (this
       breakpoint's own real minimum width) with 3 real category
       names: the nav block's own height doubled from 36px to 56px,
       confirming the wrap. white-space: nowrap on each link (below)
       stops an individual long name from wrapping internally too --
       together these keep the nav on its own single real line,
       overflowing/clipping horizontally in the rare case of a
       genuinely very long category list, rather than ever wrapping
       vertically into the logo's own space. */
    flex-wrap: nowrap;
    /* Handoff -- real bug fix, confirmed directly with Ali ("sub-
       categories are not showing as i hover... no drop down menu is
       opening"): plain overflow: hidden (this rule's own earlier
       fix, above) also clipped the real hover dropdown -- it's an
       absolutely-positioned child of a .rk-desktopnav__item inside
       this same nav, extending below this container's own box, so
       hiding overflow on both axes hid the dropdown completely
       regardless of its own opacity/pointer-events. overflow-x only
       keeps the original real fix (stop horizontal wrapping/overflow
       into the logo) without clipping anything vertical. */
    overflow-x: hidden;
  }
  /* Handoff -- real bug fix, confirmed directly with Ali against his
     own real desktop screenshot: the left nav group was right-aligned
     against the logo's own grid cell (justify-content: flex-end),
     which reads as "hugging the logo" rather than a real, spacious
     desktop nav -- especially with few real categories, where the
     links end up cramped right next to the wordmark instead of
     spread out. Centered within its own column instead, so the links
     sit in the real, balanced middle of the left half regardless of
     how many real categories exist. */
  .rk-header__desktopnav--left { grid-column: 1; justify-content: center; }
  /* Handoff -- real, explicit request, confirmed directly with Ali:
     "logo should always be centered in the middle of the website
     page in header" -- grid-column: 2 + justify-self: center only
     centers the logo within ITS OWN column, which sits between
     columns 1 and 3 (both real 1fr) -- but column 4 (the account/cart
     icons, real auto-width, not 1fr) adds extra real width on the
     right that isn't mirrored on the left, so the logo's own column
     was never actually at the true center of the full header, just
     the midpoint of columns 1-3. Taking the logo fully out of grid
     flow and centering it against the header's own real, full width
     instead makes it genuinely centered on the actual page,
     regardless of how wide the icon group or nav links are on either
     side. */
  .rk-header__logo {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    /* Handoff -- real bug fix, confirmed live: the base/mobile rule's
       own real grid-column: 2 was still in effect here -- per the
       real CSS Grid spec, an absolutely-positioned grid item that
       still has a grid-column/row set uses THAT cell as its own
       containing block, not the full grid container, so left: 50%
       was resolving against column 2's own narrow width instead of
       the header's real full width. grid-column: auto removes it
       from grid placement entirely so 50%/50% resolves against the
       real .rk-header box itself, genuinely centering it on the page. */
    grid-column: auto;
  }
  /* Mirrors the left nav exactly -- centered within its own column,
     not right-aligned against the icons (this column's own former
     nested-flex-group approach, .rk-header__rightgroup, made the gap
     to the icons unpredictable depending on how many real categories
     existed on each side). */
  .rk-header__desktopnav--right { grid-column: 3; justify-content: center; }
  .rk-header__right { grid-column: 4; display: flex; align-items: center; gap: 20px; justify-self: end; }
  .rk-desktopnav__item { position: relative; }
  .rk-desktopnav__link {
    font-size: 13px;
    letter-spacing: 1px;
    text-transform: uppercase;
    color: inherit;
    padding: 8px 0;
    display: block;
    white-space: nowrap;
  }
  .rk-header--transparent .rk-desktopnav__link { color: #fff; }
  .rk-header--transparent.is-solid .rk-desktopnav__link { color: var(--ink); }
  /* Handoff -- real, explicit request, confirmed directly with Ali:
     "i want the search button when pressed to animate transfer into
     a wider text box... when finished or pressed outside the search
     box, it gets back to first status". Anchored to its own real
     right edge so it grows LEFTWARD as it widens -- growing rightward
     here would push straight into the account/cart icons just past
     it. The "Search" link fades out as the input fades/grows in,
     rather than both being visible stacked on each other. */
  .rk-desktopsearch { position: relative; display: inline-block; }
  .rk-desktopsearch__input {
    position: absolute;
    top: 50%;
    right: 0;
    transform: translateY(-50%);
    width: 0;
    opacity: 0;
    pointer-events: none;
    border: none;
    border-bottom: 1px solid var(--ink);
    background: transparent;
    font-size: 13px;
    font-family: inherit;
    color: inherit;
    padding: 4px 0;
    outline: none;
    transition: width 280ms cubic-bezier(0.65, 0, 0.35, 1), opacity 200ms ease;
  }
  .rk-desktopsearch.is-open .rk-desktopsearch__link { opacity: 0; pointer-events: none; transition: opacity 120ms ease; }
  .rk-desktopsearch.is-open .rk-desktopsearch__input { width: 220px; opacity: 1; pointer-events: auto; }
  .rk-desktopnav__dropdown {
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    background: #fff;
    box-shadow: 0 8px 24px rgba(0,0,0,0.12);
    padding: 10px 0;
    min-width: 180px;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s ease;
    z-index: 41;
  }
  .rk-desktopnav__item:hover .rk-desktopnav__dropdown { opacity: 1; pointer-events: auto; }
  .rk-desktopnav__sublink {
    display: block;
    padding: 8px 20px;
    font-size: 13px;
    color: var(--ink);
    white-space: nowrap;
  }
  .rk-desktopnav__sublink:hover { background: var(--bg-soft, #f7f5f2); }
}

.rk-cart-btn { position: relative; }
.rk-cart-badge {
  position: absolute;
  top: -7px;
  right: -9px;
  background: var(--accent);
  color: #fff;
  font-size: 10px;
  line-height: 1;
  min-width: 16px;
  height: 16px;
  border-radius: 999px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 3px;
}

/* ---------------------------------------------------------------- */
/* Nav slide-in panel (left) + backdrop                              */
/* ---------------------------------------------------------------- */

.rk-backdrop {
  position: fixed;
  inset: 0;
  background: var(--overlay);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease;
  z-index: 45;
}
.rk-backdrop.is-open { opacity: 1; pointer-events: auto; }

.rk-navpanel {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  width: 78%;
  max-width: 360px;
  background: #fff;
  transform: translateX(-100%);
  transition: transform 0.25s ease;
  z-index: 46;
  overflow-y: auto;
  padding-bottom: 40px;
  /* Handoff -- defensive hardening, confirmed directly with Ali: an
     explicit block display + top-alignment on the panel itself and
     its list, ruling out any flex/grid centering context being
     inherited from anywhere else in the cascade. Investigated
     thoroughly and found no rule that should have been centering
     content here, but this makes top-alignment explicit and
     unambiguous rather than merely "not contradicted" -- if the
     described layout persists after this, it needs a screenshot to
     diagnose further, not another blind CSS guess. */
  display: block;
}
.rk-navpanel.is-open { transform: translateX(0); }

.rk-navpanel__search {
  margin: 22px 20px 10px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--hairline);
}
.rk-navpanel__search input {
  border: none;
  width: 100%;
  font-size: 16px;
  color: var(--ink-soft);
  outline: none;
  font-family: inherit;
}

.rk-navlist { list-style: none; margin: 6px 0 0; padding: 0; }
.rk-navlist__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  /* Handoff -- real bug fix, confirmed directly with Ali: categories
     in the side panel had visibly too much space between them.
     10px/20px (was 14px/20px) -- still comfortably tappable on
     mobile, just tighter. */
  padding: 10px 20px;
  font-size: 17px;
  color: var(--ink);
}
.rk-navlist__row.is-link { cursor: pointer; }
.rk-navlist__row.is-active { color: var(--accent); }
.rk-navlist__chevron { width: 14px; height: 14px; transition: transform 0.2s ease; flex-shrink: 0; }
.rk-navlist__row.is-open .rk-navlist__chevron { transform: rotate(180deg); }

.rk-navlist__sub {
  list-style: none;
  margin: 0;
  padding: 0 0 6px 0;
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.2s ease;
}
.rk-navlist__sub.is-open { max-height: 320px; }
.rk-navlist__sub li a {
  display: block;
  padding: 10px 20px 10px 40px;
  font-size: 15px;
  color: var(--ink);
}

/* ---------------------------------------------------------------- */
/* Cart drawer (right) -- shares the backdrop above                  */
/* ---------------------------------------------------------------- */

.rk-cartdrawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: 82%;
  max-width: 400px;
  background: var(--panel-bg);
  transform: translateX(100%);
  transition: transform 0.25s ease;
  z-index: 46;
  display: flex;
  flex-direction: column;
  padding: 22px 24px;
  overflow-y: auto;
}
.rk-cartdrawer.is-open { transform: translateX(0); }

.rk-cartdrawer__close {
  align-self: flex-end;
  background: none;
  border: none;
  font-size: 26px;
  line-height: 1;
  color: var(--ink);
  padding: 4px;
}

.rk-cartdrawer__title {
  font-size: 26px;
  font-weight: 600;
  margin: 6px 0 22px;
}

.rk-cartline {
  display: flex;
  gap: 14px;
  padding: 14px 0;
  border-bottom: 1px solid var(--hairline);
  position: relative;
}
.rk-cartline__thumb {
  width: 72px;
  height: 88px;
  background: var(--placeholder-bg);
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}
.rk-cartline__thumb svg { width: 34px; height: 34px; stroke: var(--placeholder-stroke); }
.rk-cartline__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Handoff -- real product thumbnail in the checkout summary's own
   line items, confirmed directly with Ali: this table previously
   showed name/price text only, no image at all. Small and inline
   (not a separate table column) since it's meant to sit right before
   the product name, matching the exact "image icon before a product"
   ask -- not a redesign of the summary table's own layout. */
.rk-checkout__summary-thumb {
  width: 32px;
  height: 40px;
  background: var(--placeholder-bg);
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: middle;
  margin-right: 8px;
}
.rk-checkout__summary-thumb svg { width: 16px; height: 16px; stroke: var(--placeholder-stroke); }
.rk-checkout__summary-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Handoff -- the major "confirmation + receipt" feature, confirmed
   directly with Ali: a plain, real container for the receipt preview
   built by buildReceiptHtml (checkout.html) -- the receipt's own
   inline styles carry its look, this just centers/spaces it on the
   page. */
.rk-checkout__receipt-preview { margin: 20px 0; }
/* Handoff -- real bug fix, confirmed directly with Ali: the plain
   full-page Shopping Cart table (cart.html, separate from the cart
   drawer) never rendered a product image at all, plain text only.
   Same inline-before-the-name placement as the checkout summary's own
   thumb above. */
/* Handoff -- real, explicit request, confirmed directly with Ali
   against his own real Photoshop before/after mockup: "adjust update
   button to be the same size as the qty counter field" -- both a
   real, explicit shared width (instead of each sizing to its own
   browser-default content, which made the input and button two
   different real widths) stacked directly on top of each other. */
td.rk-cart-page__qtycell input[type="number"],
td.rk-cart-page__qtycell button {
  display: block;
  width: 64px;
}
.rk-cart-page__qtycell input { margin-bottom: 6px; }
/* "remove the Remove button and replace it with an X" -- plain,
   compact, no border/background, so it costs the item-name column
   almost none of its own real width (that column badly needed it --
   see cart.html's own docstring on this same change). */
td button.rk-cart-page__remove {
  background: none;
  border: none;
  font-size: 20px;
  line-height: 1;
  color: var(--ink-soft);
  cursor: pointer;
  padding: 4px;
}
td button.rk-cart-page__remove:hover { color: var(--danger); }

.rk-cart-page__thumb {
  width: 32px;
  height: 40px;
  background: var(--placeholder-bg);
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  vertical-align: middle;
  margin-right: 8px;
}
.rk-cart-page__thumb svg { width: 16px; height: 16px; stroke: var(--placeholder-stroke); }
.rk-cart-page__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.rk-cartline__body { flex: 1; }
.rk-cartline__sku { font-size: 15px; color: var(--ink); margin: 0 0 8px; }
.rk-cartline__qtyprice { font-size: 15px; color: var(--ink); }
/* Handoff -- real bug fix, confirmed directly with Ali ("if i open a
   shopping cart shortcut... it doesnt have the remove or X"): this
   button's own real SVG (ICONS.close) never carries its own stroke
   color or size -- every other icon in this file (e.g.
   .rk-cartline__thumb svg just above) sets both explicitly via CSS,
   since the raw SVG markup itself is deliberately colorless so CSS
   controls it. This one rule was missing that, so the X's own real
   <line> elements rendered with SVG's own true default (stroke: none)
   -- completely invisible, not just small or faint -- even though the
   button/SVG were both genuinely present in the DOM (confirmed via a
   real browser test: 0 visible pixels, but the click handler was
   there and functional the whole time). */
.rk-cartline__remove {
  position: absolute;
  top: 14px;
  right: 0;
  background: none;
  border: none;
  color: var(--accent);
  font-size: 15px;
  cursor: pointer;
}
.rk-cartline__remove svg { width: 16px; height: 16px; stroke: var(--accent); }

.rk-cartdrawer__subtotal {
  display: flex;
  justify-content: space-between;
  font-weight: 700;
  font-size: 17px;
  padding: 18px 0;
}

.rk-btn {
  display: block;
  width: 100%;
  text-align: center;
  padding: 15px;
  font-size: 15px;
  border-radius: 2px;
  border: 1px solid var(--btn-dark);
  background: #fff;
  color: var(--btn-dark);
  margin-bottom: 12px;
}
.rk-btn--solid { background: var(--btn-dark); color: #fff; }
.rk-btn--solid:hover { background: var(--btn-dark-hover); }

.rk-cartdrawer__empty { color: var(--ink-soft); padding: 30px 0; text-align: center; }

/* ---------------------------------------------------------------- */
/* Homepage: real vertical fullpage slider (ysl.com-style), confirmed */
/* directly with Ali -- see app.js's own initHomeFullpage.            */
/* ---------------------------------------------------------------- */

.rk-fullpage {
  position: relative;
  height: 100vh;
  overflow: hidden;
}
/* Handoff -- real bug fix, confirmed directly with Ali, who described
   the exact real difference from the real ysl.com reference: our own
   real transition was a "push" (both the outgoing and incoming slide
   move together, like a single filmstrip shifting) -- the real
   reference instead "covers": every panel stays in its own real,
   fixed stacking position and NEVER moves once revealed; only the ONE
   panel currently sliding animates, on top of (z-index) whatever's
   already sitting still underneath it. Scrolling forward slides the
   next real panel up from below to cover the current one (which
   itself does not move); scrolling back slides that same covering
   panel back down out of the way, revealing the one underneath it --
   which, again, never moved. No shared track transform anymore (see
   below) -- each panel controls its own real transform/z-index.
   Speed/easing unchanged, same real values confirmed earlier against
   the reference's own recording. */
.rk-fp-track {
  position: relative;
  height: 100%;
}
.rk-fp-panel {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100vh;
  min-height: 100vh;
  overflow: hidden;
  transition: transform 320ms cubic-bezier(0.65, 0, 0.35, 1);
  will-change: transform;
  /* Handoff -- real bug fix, confirmed directly with Ali ("shop by
     category section comes up covering the only visible card from
     the middle only... the last scroll is the footer also just
     covering the slide from the middle"): this panel never had its
     own real, opaque background at all -- only its own inner content
     (the category tile row, the footer block) is actually opaque, so
     "covering" the panel underneath only ever blocked that one real
     strip in the middle, leaving the previous slide fully visible
     everywhere else around it. A real background here means the
     panel itself genuinely covers the full real screen the moment it
     slides into place, not just its own content's own real bounding
     box. The hero panel's own real photo/video already fills its
     entire box regardless, so this is never visible there. */
  background: var(--page-bg);
}
/* The footer's real content can genuinely exceed one screen's height
   (address/social/newsletter block) -- unlike the hero/category/
   featured panels, which are deliberately composed to fit, the footer
   is allowed its own internal scroll rather than clipping real
   content or forcing the whole page taller than 100vh. */
/* Handoff -- real, explicit request, confirmed directly with Ali:
   "footer should cover the whole page as if it is a slider" --
   align-items: center (this rule's own earlier real approach) let
   the real <footer> element sit shorter than 100vh, centered, with
   this panel's own real page-background color showing above/below
   it instead of the footer's own real dark background filling the
   whole real screen like every other slide does. height: 100% makes
   the real <footer> element itself the full height of its own
   panel -- overflow-y: auto stays, for the rare case its own real
   content (address/social/newsletter) genuinely exceeds one screen. */
.rk-fp-panel--footer { overflow-y: auto; }
.rk-fp-panel--footer > footer { width: 100%; height: 100%; display: flex; flex-direction: column; justify-content: center; }
/* The two content panels (category/featured) are real sections, not
   full-bleed photos -- centered vertically within their own real
   full-screen slide so they don't look pinned to the top of an
   otherwise-empty screen. */
.rk-section.rk-fp-panel { display: flex; flex-direction: column; justify-content: center; }

/* Handoff -- real bug fix, confirmed directly with Ali against his own
   screen recording of the real reference site: it has NO visible
   arrow buttons at all, gesture/scroll only -- the .rk-fp-arrow rules
   that used to live here are removed entirely, not just hidden, along
   with initHomeFullpage's own click handlers for them (app.js). */

/* ---------------------------------------------------------------- */
/* Homepage hero                                                     */
/* ---------------------------------------------------------------- */

.rk-hero {
  /* Handoff -- real bug fix, confirmed directly with Ali ("home page
     slides over each other is not working at all" -- reproduced live
     with 4 real, visually distinct test slides: scrolling never moved
     off slide 1 at all): this rule's own real position: relative --
     same specificity as .rk-fp-panel's own real position: absolute,
     defined earlier in this file -- was winning by pure cascade
     order, silently overriding it for every hero panel specifically
     (every hero panel carries both classes). That put every real hero
     panel back in NORMAL DOCUMENT FLOW, stacked one below the next
     instead of all overlapping at the same real position -- so
     "covering" the previous slide never had anything to actually
     cover; the covering panel was simply somewhere else on the page
     entirely. Removed here -- .rk-fp-panel's own position: absolute
     already establishes the real positioning context this rule's
     children (the caption/CTA/placeholder) need, so nothing here was
     actually relying on this rule setting it a second time. */
  height: 100vh;
  min-height: 520px;
  overflow: hidden;
}
.rk-hero .rk-ph { position: absolute; inset: 0; }
/* Handoff -- real bug fix, confirmed directly with Ali: replaces the
   old giant 22vw "RICKEZZA" text watermark sprawled across the hero.
   The reference site's own real hero has zero decorative text
   overlay competing with the photo -- "the only visible chrome is a
   single line of text navigation" and "tiny uppercase captions float
   near the bottom edge." The header's own logo already carries brand
   identity; this caption is now genuinely tiny, uppercase, and
   anchored near the bottom like the reference, not a second,
   oversized logo lettered across the photo. Absolutely positioned
   (not flex order) so the caption-above-CTA stacking is exact and
   explicit, not dependent on flex item ordering. Centered
   horizontally (was left-aligned) -- confirmed directly with Ali
   against his own screen recording of the real reference site, which
   centers both the caption and the CTA under it. */
.rk-hero__caption {
  position: absolute;
  left: 50%;
  bottom: 66px;
  transform: translateX(-50%);
  margin: 0;
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 3px;
  text-transform: uppercase;
  text-align: center;
  color: #fff;
  pointer-events: none;
  white-space: nowrap;
}
.rk-hero__cta {
  position: absolute;
  left: 50%;
  bottom: 34px;
  transform: translateX(-50%);
  padding: 0 0 4px;
  /* Handoff -- real bug fix, confirmed directly with Ali: the old
     filled/bordered pill button ("Solid, not translucent... a solid
     pale fill") was exactly the kind of chrome the reference site
     never has -- "zero shadows, zero borders, zero decoration."
     Replaced with a plain, minimal text link with a thin underline,
     matching the reference's own "tiny uppercase captions." */
  background: none;
  border: none;
  border-bottom: 1px solid rgba(255,255,255,0.7);
  color: #fff;
  font-size: 12px;
  letter-spacing: 2px;
  text-transform: uppercase;
  text-align: center;
  white-space: nowrap;
}
.rk-hero__cta:hover { border-bottom-color: #fff; opacity: 0.85; }

/* Handoff -- website content management, confirmed directly with
   Ali. Real, Admin-managed carousel replacing the old single static
   placeholder -- see app.js's own renderHomeCarousel. Slides stack
   absolutely and cross-fade via opacity (no layout thrash, no
   dependency on a carousel library); dots overlay the bottom center,
   above the CTA's own bottom-left position so the two never collide. */
.rk-hero__track { position: absolute; inset: 0; }
.rk-hero__slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.6s ease;
  pointer-events: none;
}
.rk-hero__slide.is-active { opacity: 1; pointer-events: auto; }
.rk-hero__media, .rk-hero__slidelink { display: block; width: 100%; height: 100%; object-fit: cover; }
/* Handoff -- real, explicit request, confirmed directly with Ali:
   "visual margins for mobile view and desktop view and ability to
   move the margin within the image to show the wanted part of the
   images" -- mobile-first: the real --mobile-focal custom property
   (set per-slide inline by app.js's own renderHomeCarousel) drives
   object-position by default; the desktop media query below swaps to
   --desktop-focal instead, matching the same real min-width:960px
   breakpoint every other real desktop override in this file already
   uses. The var()'s own 50% 50% fallback keeps this correct even for
   a slide from before this feature existed, with no focal point set
   on it at all. */
.rk-hero__media { object-position: var(--mobile-focal, 50% 50%); }
@media (min-width: 960px) {
  .rk-hero__media { object-position: var(--desktop-focal, 50% 50%); }
}
.rk-hero__slidelink { position: relative; }
.rk-hero__dots {
  position: absolute;
  left: 50%;
  bottom: 22px;
  transform: translateX(-50%);
  display: flex;
  gap: 8px;
  z-index: 2;
}
.rk-hero__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  border: 1px solid rgba(255,255,255,0.8);
  background: transparent;
  padding: 0;
  cursor: pointer;
}
.rk-hero__dot.is-active { background: #fff; }

.rk-section {
  padding: 34px 20px 10px;
}
.rk-section__title {
  font-size: 13px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--ink-soft);
  text-align: center;
  margin: 0 0 18px;
}
/* ---------------------------------------------------------------- */
/* Homepage: "Shop by Category" rail (data-driven, see app.js's       */
/* renderHomeCategoryRail -- real category count, not a fixed 3-up)   */
/* ---------------------------------------------------------------- */

.rk-familyrail {
  display: flex;
  gap: 14px;
  overflow-x: auto;
  padding: 4px 20px 10px;
  -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity;
}
.rk-familytile {
  flex: 0 0 auto;
  width: 128px;
  scroll-snap-align: start;
  color: inherit;
}
.rk-familytile__img {
  width: 128px;
  height: 160px;
  border-radius: 2px;
  overflow: hidden;
  /* Handoff -- real bug fix, confirmed directly with Ali ("i selected
     the colors i want... but the colors didnt change") -- --bg-soft's
     own real admin label explicitly names "category tiles" as an
     example of what it controls; wired in here as the real fallback
     shown while a real photo loads/if one is missing, so the color
     genuinely does something visible here too, not just on two hover
     states nobody's likely to sit on long enough to notice. */
  background: var(--bg-soft);
}
/* Handoff -- real bug fix, confirmed directly with Ali: a real
   uploaded category photo has no natural relationship to this tile's
   own 128x160px size -- without an explicit rule constraining the
   <img> tag itself (not just its container), it rendered at its own
   full, uncropped resolution, breaking out of the tile entirely and
   overlapping neighboring tiles. object-fit: cover crops to fill the
   tile without distorting the photo's own aspect ratio, same
   convention as every other real product/category photo elsewhere in
   this codebase. */
.rk-familytile__img img, .rk-familytile__img .rk-ph { width: 100%; height: 100%; object-fit: cover; display: block; }
.rk-familytile__name {
  margin-top: 10px;
  font-size: 12px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--ink);
  text-align: center;
}

/* ---------------------------------------------------------------- */
/* Homepage: Featured / New Arrivals rail (data-driven, see app.js's  */
/* renderHomeFeaturedRail -- real in-stock catalog items, capped for  */
/* display, never padded/faked when the catalog has fewer)            */
/* ---------------------------------------------------------------- */

.rk-featurerail {
  display: flex;
  gap: 14px;
  overflow-x: auto;
  padding: 4px 20px 10px;
  -webkit-overflow-scrolling: touch;
  scroll-snap-type: x proximity;
}
.rk-featuretile {
  flex: 0 0 auto;
  width: 62vw;
  max-width: 230px;
  scroll-snap-align: start;
  display: flex;
  flex-direction: column;
}
.rk-featuretile__media { display: block; }
.rk-featuretile__media, .rk-featuretile__media .rk-ph {
  width: 100%;
  aspect-ratio: 4/5;
  border-radius: 2px;
}
.rk-featuretile__media img { width: 100%; height: 100%; object-fit: cover; display: block; border-radius: 2px; }
.rk-featuretile__brand {
  margin-top: 10px;
  font-size: 11px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.rk-featuretile__name {
  display: block;
  margin-top: 2px;
  font-size: 13px;
  color: var(--accent);
}
.rk-featuretile__price { margin-top: 2px; font-size: 13px; font-weight: 600; color: var(--accent); }
.rk-featuretile__price s { color: var(--ink-mute); font-weight: 400; margin-right: 6px; }
.rk-featuretile__add {
  margin-top: 10px;
  border: 1px solid var(--btn-dark);
  background: #fff;
  color: var(--btn-dark);
  padding: 9px 6px;
  font-size: 11px;
  letter-spacing: 1px;
  text-transform: uppercase;
}
.rk-featuretile__add:hover { background: var(--btn-dark); color: #fff; }

/* ---------------------------------------------------------------- */
/* Homepage: brand/craft story block (static editorial copy -- see   */
/* the redesign report re: no real photo/video asset exists yet)      */
/* ---------------------------------------------------------------- */

.rk-craft {
  display: flex;
  flex-direction: column;
  margin-top: 20px;
}
.rk-craft__img { width: 100%; aspect-ratio: 4/3; }
.rk-craft__img .rk-ph { width: 100%; height: 100%; }
.rk-craft__body { padding: 26px 24px 6px; text-align: center; }
.rk-craft__eyebrow {
  font-size: 12px;
  letter-spacing: 2px;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 10px;
}
.rk-craft__copy { font-size: 14px; line-height: 1.7; color: var(--ink-soft); max-width: 460px; margin: 0 auto 18px; }
.rk-craft__cta {
  display: inline-block;
  padding: 12px 26px;
  border: 1px solid var(--btn-dark);
  color: var(--btn-dark);
  font-size: 12px;
  letter-spacing: 2px;
  text-transform: uppercase;
}
.rk-craft__cta:hover { background: var(--btn-dark); color: #fff; }

@media (min-width: 760px) {
  .rk-craft { flex-direction: row-reverse; align-items: center; }
  .rk-craft__img { width: 50%; aspect-ratio: 1/1; }
  .rk-craft__body { width: 50%; text-align: left; padding: 40px; }
  .rk-craft__copy { margin: 0 0 18px; }
}

/* ---------------------------------------------------------------- */
/* Footer (site-wide across homepage/catalog/product -- app.js's      */
/* renderFooter). No real newsletter backend exists yet (see report)  */
/* -- the form gives friendly inline confirmation only, doesn't       */
/* claim to persist anywhere.                                         */
/* ---------------------------------------------------------------- */

.rk-footer { margin-top: 40px; background: var(--footer-bg); color: var(--footer-text); }
.rk-footer__newsletter {
  max-width: 420px;
  margin: 0 auto;
  padding: 52px 24px 40px;
  text-align: center;
}
.rk-footer__newsletter-title {
  font-family: var(--font-display);
  font-size: 24px;
  margin: 0 0 8px;
  color: #fff;
}
.rk-footer__newsletter-sub { font-size: 13px; color: rgba(255,255,255,0.55); margin: 0 0 22px; }
.rk-footer__newsletter-form { display: flex; border-bottom: 1px solid rgba(255,255,255,0.35); padding-bottom: 10px; }
.rk-footer__newsletter-form input {
  flex: 1;
  background: none;
  border: none;
  outline: none;
  color: #fff;
  font-size: 14px;
  font-family: inherit;
}
.rk-footer__newsletter-form input::placeholder { color: rgba(255,255,255,0.45); }
.rk-footer__newsletter-form button {
  background: none;
  border: none;
  color: #fff;
  font-size: 12px;
  letter-spacing: 1.5px;
  text-transform: uppercase;
}
.rk-footer__newsletter-note { font-size: 12px; color: var(--accent); min-height: 16px; margin: 10px 0 0; }
/* Handoff -- website content management, confirmed directly with
   Ali. Real address/phone/email + social links, shown only when
   actually set -- see renderFooter's own docstring. */
.rk-footer__contact { margin-top: 18px; }
.rk-footer__contact-line { font-size: 13px; margin: 2px 0; opacity: 0.85; }
.rk-footer__contact-line a { color: inherit; }
.rk-footer__social { margin-top: 10px; display: flex; gap: 14px; flex-wrap: wrap; }
.rk-footer__social a { font-size: 12px; letter-spacing: 1px; text-transform: uppercase; opacity: 0.85; }
.rk-footer__social a:hover { opacity: 1; text-decoration: underline; }
.rk-footer__bottom {
  border-top: 1px solid rgba(255,255,255,0.12);
  padding: 20px 24px 28px;
  text-align: center;
}
.rk-footer__logo { font-family: var(--font-display); font-size: 18px; color: #fff; margin-bottom: 10px; }
.rk-footer__copyright { font-size: 11px; color: rgba(255,255,255,0.45); margin: 0; }

/* ---------------------------------------------------------------- */
/* Catalog                                                            */
/* ---------------------------------------------------------------- */

.rk-page-title {
  text-align: center;
  font-size: 13px;
  letter-spacing: 3px;
  text-transform: uppercase;
  color: var(--ink);
  margin: 26px 0 4px;
}

/* Real category/listing pages (reference §4): "Pinterest-style masonry
   photo feed" -- confirmed a real, deliberate brand-feel decision Ali
   wants kept, NOT switched to a conventional grid despite the
   reference document's own recommendation leaning that way. CSS
   multi-column layout gives the genuine staggered effect (tiles of
   different photo heights naturally interlock) without hand-rolled JS
   layout math -- the real technique for this pattern, not a fixed-grid
   approximation of it. */

.rk-controls {
  max-width: 480px;
  margin: 18px auto 8px;
  padding: 0 16px;
}
.rk-controls__row { margin-bottom: 18px; }
.rk-controls__label {
  font-size: 13px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 10px;
}
/* Real brand-colored range slider -- replaces the old site's unstyled
   Bootstrap-blue default (#1a73e8, confirmed bug, reference §9 item
   10). Cross-browser range styling needs the vendor-prefixed thumb/
   track rules below; `accent-color` alone (Chrome/Firefox only) isn't
   enough to guarantee the fix on every real device Ali's shoppers use. */
.rk-controls input[type="range"] {
  width: 100%;
  accent-color: var(--accent);
  height: 4px;
  background: var(--hairline);
  border-radius: 2px;
  -webkit-appearance: none;
  appearance: none;
}
.rk-controls input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--accent);
  cursor: pointer;
  border: 2px solid #fff;
  box-shadow: 0 0 0 1px var(--accent);
}
.rk-controls input[type="range"]::-moz-range-thumb {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  background: var(--accent);
  cursor: pointer;
  border: 2px solid #fff;
  box-shadow: 0 0 0 1px var(--accent);
}
.rk-controls__divider { border: none; border-top: 1px solid var(--hairline); margin-top: 10px; }

.rk-catalog-status { text-align: center; color: var(--ink-soft); font-size: 14px; margin: 10px 0; }

/* Real filter chips -- Price range/Color/Size (reference §4's
   legitimate filters). Deliberately NO Brand filter unless real
   brand/collection data exists to filter by -- the old site's Brand
   filter was fake demo data (Samsung, LG, Toyota; §9 item 7,
   confirmed leftover platform seed data), not something to replicate
   even styled correctly. */
.rk-filterbar {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding: 4px 16px 14px;
  -webkit-overflow-scrolling: touch;
}
.rk-filterchip {
  flex-shrink: 0;
  border: 1px solid var(--hairline);
  background: #fff;
  color: var(--ink);
  padding: 8px 16px;
  font-size: 12px;
  letter-spacing: 0.5px;
  border-radius: 20px;
  white-space: nowrap;
}
.rk-filterchip.is-active { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }
/* Handoff -- real, explicit request, confirmed directly with Ali:
   "create a filter icon to the right" -- margin-left: auto pushes
   it to the real far right of the bar regardless of how many chips
   are currently shown/hidden to its left. */
.rk-filterbar__togglebtn {
  flex-shrink: 0;
  margin-left: auto;
  width: 34px;
  height: 34px;
  border: 1px solid var(--hairline);
  border-radius: 50%;
  background: #fff;
  color: var(--ink);
  display: flex;
  align-items: center;
  justify-content: center;
}
.rk-filterbar__togglebtn.is-active { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }
.rk-filterbar__togglebtn svg { width: 16px; height: 16px; stroke: currentColor; }

.rk-filterpanel {
  max-width: 480px;
  margin: 0 auto;
  padding: 14px 16px;
  border-bottom: 1px solid var(--hairline);
  display: none;
}
.rk-filterpanel.is-open { display: block; }
.rk-filterpanel__row { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
.rk-filterpanel__swatch {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 1px solid var(--hairline);
  cursor: pointer;
  padding: 0;
}
.rk-filterpanel__swatch.is-selected { border: 2px solid var(--accent); background: var(--accent-soft); }
.rk-filterpanel__sizebtn {
  border: 1px solid var(--hairline);
  background: #fff;
  padding: 6px 12px;
  font-size: 12px;
  cursor: pointer;
}
.rk-filterpanel__sizebtn.is-selected { border-color: var(--accent); color: var(--accent); background: var(--accent-soft); }
.rk-filterpanel__apply {
  width: 100%;
  border: none;
  background: var(--btn-dark);
  color: #fff;
  padding: 12px;
  font-size: 13px;
  letter-spacing: 1px;
  text-transform: uppercase;
}

/* Handoff -- real bug fix, confirmed directly with Ali: the old
   column-count "masonry" layout (each tile's own photo height decided
   where it landed) is genuinely why tiles looked left-aligned/
   uneven -- column-count fills columns top-to-bottom independently,
   it was never a real row-based grid to begin with, so there was no
   "centering" to fix within that approach. Replaced with a real CSS
   grid: fixed column count per breakpoint (2 up to tablet, 4 at
   desktop -- Ali's own explicit spec, replacing the old 2/3/4 masonry
   steps), and every tile's own image now uses a fixed aspect-ratio
   (see .rk-tile__img below) so rows genuinely line up -- a real grid
   with variable-height content wouldn't look aligned either. */
.rk-grid {
  /* Handoff -- real, explicit request, confirmed directly with Ali:
     "always in mobile view or desktop view, the last finished
     product card should be in the middle if it is alone on the
     page... if the last row has 1 or 2 product cards, then also
     center them in the middle" -- CSS grid has no real way to center
     an incomplete last row on its own; flexbox does, natively, via
     justify-content: center on wrapped items. Each real tile below
     gets an explicit width matching this breakpoint's own real
     column count (2 here, 4 at desktop) so the visual layout is
     identical to the grid it replaces in every other real respect --
     only the incomplete-last-row behavior actually changes. */
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 2px;
  padding: 0 2px;
  margin-top: 4px;
}
.rk-grid > .rk-tile {
  /* 2 columns, gap: 2px between them (1 gap per row) -- matches this
     breakpoint's own real .rk-grid gap above exactly. */
  width: calc((100% - 2px) / 2);
}
.rk-tile {
  width: 100%;
  /* Handoff -- real bug fix, found live from a real mobile screenshot
     Ali sent: on a narrow 2-column mobile grid, the fanned variant
     thumbnail row's own fixed, non-shrinking width (flex-shrink: 0)
     was forcing this tile's own grid TRACK wider than its real 1fr
     share (CSS grid items default to min-width: auto, not 0, so a
     child's min-content size can silently inflate the whole column) --
     the result was two visibly different-width columns and the whole
     grid overflowing past the real viewport edge, cutting off the
     second column's own card entirely. min-width: 0 here is the real,
     standard fix: lets this tile actually shrink to its real 1fr grid
     track instead of forcing the track to grow around it.
     Confirmed live: before this fix, the two columns measured 253px
     and 152px (should both be equal); after, both grid columns render
     at their real, equal, in-viewport width. */
  min-width: 0;
  background: #fff;
  padding-bottom: 14px;
}
.rk-tile__img {
  aspect-ratio: 3 / 4;
  background: var(--placeholder-bg);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  /* Handoff -- real, explicit request, confirmed directly with Ali:
     "add to favorite... an empty heart icon on the top right" --
     anchors the real heart button (see .rk-favorite-btn below)
     against this image's own box, not the whole tile. */
  position: relative;
}
.rk-tile__img svg { width: 30%; height: 30%; stroke: var(--placeholder-stroke); }
.rk-tile__img img { width: 100%; height: 100%; display: block; object-fit: cover; }
/* Handoff -- real, explicit request, confirmed directly with Ali:
   "add to favorite... an empty heart icon on the top right, when
   pressing it, the heart will turn to a color i will pick in website
   colors in admin". Empty/outline by default (stroke: currentColor,
   fill: none -- see ICONS.heart's own real SVG); .is-favorited swaps
   to a real, filled heart in the real, admin-picked
   --favorite-heart color -- both states share the exact same SVG
   markup, never swapped for a second icon. z-index above the image
   itself and any placeholder icon, but below nothing else real on
   this tile (no dropdown/overlay on a catalog tile competes for this
   corner).

   Handoff -- real, explicit follow-up request, confirmed directly
   with Ali: "decrease the favorite button's opacity to 50% and
   remove the circle around it, just keep the internal heart" -- the
   white circular backdrop (background + border-radius) is gone, and
   the whole button sits at 50% opacity so the heart itself reads as
   a soft overlay directly on the image rather than a separate button
   chrome floating above it. */
.rk-favorite-btn {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 2;
  width: 30px;
  height: 30px;
  border: none;
  background: none;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ink-mute);
  cursor: pointer;
  opacity: 0.5;
}
.rk-favorite-btn svg { width: 16px; height: 16px; }
.rk-favorite-btn.is-favorited { color: var(--favorite-heart); }
.rk-favorite-btn.is-favorited svg { fill: currentColor; }
/* Handoff -- real bug fix / direct reversal, confirmed directly with
   Ali against his own Photoshop mockup (product_card.zip): the main
   hero photo above stays its own separate, full-size image -- the
   variant thumbnails below sit in their own real row next to name/
   price instead of replacing it (an earlier round's interpretation,
   now corrected). infotext (name/brand/price) and the thumbs share
   this one row, name/price on the left, thumbs on the right, exactly
   matching the mockup's own layout. */
.rk-tile__inforow {
  display: flex;
  /* Handoff -- real bug fix, confirmed directly with Ali against his
     own before/after screenshots ("the names are now each one on
     level, they should stay on the same level"): flex-end bottom-
     aligned name/price against the fan -- since the fan (102px tall)
     is much taller than the name/price text block (~46px), that
     pushed the text down by the real height difference, so a tile
     with a fan showed its name noticeably lower than a tile without
     one. flex-start top-aligns both instead, so every tile's name
     starts at the exact same real row position regardless of whether
     it has a fan or not. */
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 10px 0;
  min-width: 0;
}
.rk-tile__infotext { min-width: 0; }
/* Handoff -- real "fanned mini variant thumbnails" feature, confirmed
   directly with Ali against his own Photoshop mockup: up to 4 real
   variant photo thumbnails in one single horizontal row, NEVER
   wrapping, each overlapping the previous one (a real fanned deck, not
   a 2x2 grid or independent tiles), same top/bottom alignment. flex +
   nowrap with real negative margins for the overlap, not absolute
   positioning -- simpler to keep genuinely responsive since each
   card's own width/overlap are both set in real %, not fixed px. */
/* Handoff -- real, explicit request, confirmed directly with Ali: with
   Add to Bag removed from a multi-variant tile (see catalog.html's own
   addRowHtml), the fan grows to fill that real, freed vertical space
   instead of leaving it empty -- measured live: the removed add-row
   was exactly 46px tall, so the fan's own height grows by that same
   amount (56 -> 102px), width scaled up proportionally to keep the
   same real look, just bigger. A genuinely single-variant tile never
   shows this fan at all (sibling_images only exists when sibling_count
   > 1), so there's no competing size need to balance against here. */
.rk-varthumbs {
  display: flex;
  flex-wrap: nowrap;
  flex-shrink: 0;
  width: 153px;
  height: 102px;
  /* Handoff -- real, explicit request, confirmed directly with Ali
     against his own before/after screenshots: "move the stack a
     little bit to the right, so if we have 1 variant, it will show
     on the far end at right, if we have 2, they will be that far end
     card with one to her left" -- with fewer than 4 real siblings,
     the cards used to sit flush against this container's own LEFT
     edge (flex's own real default), leaving empty space on the
     right. flex-end anchors the group to this container's own real
     right edge instead, growing leftward as more real cards are
     added, so the rightmost card's own right edge is always in the
     same real place regardless of count. */
  justify-content: flex-end;
}
.rk-varthumb {
  width: 40%;
  height: 100%;
  flex-shrink: 0;
  border: 1.5px solid #fff;
  box-shadow: 0 1px 3px rgba(0,0,0,0.15);
  overflow: hidden;
  background: var(--placeholder-bg);
}
/* Real, solved-for pairing (card width + 3 x (card width - overlap) =
   100) so 4 cards exactly fill the stack's own width with an even
   overlap -- same math as the earlier catalog-grid fan attempt, kept
   here since it's still correct, just applied to a smaller component
   now. */
.rk-varthumb:not(:first-child) { margin-left: -20%; }
.rk-varthumb:nth-child(1) { z-index: 4; }
.rk-varthumb:nth-child(2) { z-index: 3; }
.rk-varthumb:nth-child(3) { z-index: 2; }
.rk-varthumb:nth-child(4) { z-index: 1; }
/* Handoff -- real, explicit instruction from Ali: each variant
   thumbnail's own photo is zoomed to 150% and anchored to the top of
   the frame, not centered -- most of these product photos are shot
   with the garment/pattern's own most distinctive part near the top,
   so a plain centered crop wastes the small thumbnail's own limited
   space on empty lower fabric/background. object-fit: cover already
   crops to fill; scale(1.5) is the real zoom on top of that (not a
   180%+ background-size hack, since these are real <img> tags, not
   CSS background images), object-position: top anchors the crop to
   the top edge instead of the vertical center. Explicitly confirmed
   directly with Ali as NOT applying to the product detail page's own
   variant selector (product.html's renderSwatches) -- that one stays
   as already built. */
.rk-varthumb img { width: 100%; height: 100%; display: block; object-fit: cover; object-position: top; transform: scale(1.5); transform-origin: top; }
.rk-varthumb svg { width: 100%; height: 100%; padding: 22%; box-sizing: border-box; stroke: var(--placeholder-stroke); }
.rk-tile__brand {
  font-size: 11px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--ink-soft);
}
/* Real: product name/price text renders in the brand accent color
   (reference §1). */
.rk-tile__name { font-size: 14px; padding: 2px 0 4px; color: var(--accent); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rk-tile__price { font-size: 14px; color: var(--accent); font-weight: 600; }
.rk-tile__price s { color: var(--ink-mute); font-weight: 400; margin-right: 6px; }
/* Handoff -- real, explicit request, confirmed directly with Ali
   against his own before/after screenshots: "move the add to bag to
   the right with the counter" -- the button used to stretch
   (flex: 1) to fill the entire row; both it and the qty input now
   size to their own real content and sit together at the row's own
   right edge instead. */
.rk-tile__addrow { padding: 10px 10px 0; display: flex; gap: 8px; align-items: center; justify-content: flex-end; }
.rk-tile__addrow input {
  width: 46px;
  border: 1px solid var(--hairline);
  padding: 6px;
  font-size: 13px;
}
.rk-tile__addrow button {
  border: 1px solid var(--btn-dark);
  background: #fff;
  color: var(--btn-dark);
  padding: 8px 14px;
  font-size: 12px;
  letter-spacing: 1px;
  text-transform: uppercase;
  white-space: nowrap;
}
.rk-tile__addrow button:hover { background: var(--btn-dark); color: #fff; }

/* DISPATCH-18 §3a -- a tile whose design has other in-stock colors
   (sibling_count >= 2, see catalog.html's renderCatalog) wraps its
   image/brand/name/price in a real link into the product page, so a
   shopper can still reach the gallery/sibling-switcher (§3b) from any
   one color's card -- while the qty/add-to-cart row underneath stays
   OUTSIDE this link, so it keeps working as its own direct action
   without triggering navigation (matches the reference site's card
   being tappable AND carrying its own persistent "add to bag", see
   the redesign research doc). A single-variant tile (sibling_count
   === 1) never gets this wrapper -- unchanged, plain inline-add card. */
.rk-tile__linkoverlay {
  display: block;
  color: inherit;
  text-decoration: none;
  cursor: pointer;
}

@media (min-width: 960px) {
  .rk-grid > .rk-tile {
    /* 4 columns, 3 gaps of 2px between them per row -- matches this
       breakpoint's own real .rk-grid gap exactly. */
    width: calc((100% - 6px) / 4);
  }
}

/* ---------------------------------------------------------------- */
/* Product / variant-selection screen (Addendum 14)                  */
/* ---------------------------------------------------------------- */

/* Real product page (reference §5): "strong photography-led layout --
   large image + thumbnail strip + minimal right-column info: name,
   price, stock badge, variant selector, Share/Add to Cart." Mobile-
   first: image on top full-width, info stacks below it (the "right
   column" becomes a below-image block at this width; a real side-by-
   side column layout only kicks in above tablet width, since ~99% of
   real traffic is phone-width per Ali). */

.rk-productpage { max-width: 640px; margin: 0 auto; padding: 0 0 60px; }
/* Handoff -- real bug fix, confirmed directly with Ali: a real way
   back to the catalog page a shopper actually came from -- see
   product.html's own real history.back() behavior. */
.rk-productpage__back {
  display: inline-block;
  padding: 16px 16px 0;
  font-size: 13px;
  letter-spacing: 0.5px;
  color: var(--ink-soft);
}
.rk-productpage__back:hover { color: var(--ink); }

.rk-productpage__gallery {
  margin-bottom: 4px;
  /* Handoff -- real, explicit request, confirmed directly with Ali:
     "add to favorite... an empty heart icon on the top right" --
     anchors the real favorite button (below) against this real
     gallery box. */
  position: relative;
}
.rk-productpage__favorite { top: 12px; right: 12px; }
.rk-productpage__img {
  position: relative; /* DISPATCH-18 §3b -- anchors the absolutely-
     positioned crossfade layers below; aspect-ratio keeps giving this
     box its real height since the layers themselves don't. */
  aspect-ratio: 4/5;
  background: var(--placeholder-bg);
  overflow: hidden;
}
/* DISPATCH-18 §3b -- real crossfade layers (see product.html's
   renderGallery/showImage): each swap stacks a new layer on top and
   fades it in over the outgoing one, rather than a hard innerHTML
   swap. ~250ms sits inside the research doc's confirmed 200-300ms
   convention for PDP image-swap crossfades. */
.rk-productpage__imglayer {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  transition: opacity 250ms ease-in-out;
}
.rk-productpage__imglayer.is-visible { opacity: 1; }
/* Handoff: real bug found and fixed -- object-fit: cover was cropping
   every product photo to fill this box's fixed aspect-ratio, and on
   mobile that box was forced to a literal square (aspect-ratio: 1/1
   below), confirmed as exactly the "square view" Ali described.
   object-fit: contain shows the real, whole image at its own natural
   proportions -- letterboxed within the box rather than cropped --
   which is what "keep the same size of the images without
   auto-cropping" means in practice for a fixed-height gallery box
   (the crossfade layers are absolutely positioned and don't
   contribute to the parent's own height, so the box still needs some
   real height to size against -- see the box's own aspect-ratio
   comment above -- but nothing inside it gets cropped anymore). */
.rk-productpage__imglayer img { width: 100%; height: 100%; object-fit: contain; }
.rk-productpage__imglayer svg { width: 30%; height: 30%; stroke: var(--placeholder-stroke); }

.rk-productpage__thumbs {
  display: flex;
  gap: 8px;
  padding: 10px 16px;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}
.rk-productpage__thumb {
  width: 56px;
  height: 68px;
  flex-shrink: 0;
  background: var(--placeholder-bg);
  border: 1px solid var(--hairline);
  padding: 0;
  overflow: hidden;
  cursor: pointer;
}
.rk-productpage__thumb.is-active { border-color: var(--accent); border-width: 2px; }
.rk-productpage__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Handoff: real click-to-zoom lightbox for the main product image
   (see product.html's openLightbox). cursor: zoom-in on the trigger
   hints it's clickable before the person ever hovers the lightbox
   itself. */
.rk-productpage__img { cursor: zoom-in; }
.rk-lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(20, 18, 16, 0.92);
  display: flex;
  align-items: center;
  justify-content: center;
}
.rk-lightbox[hidden] { display: none; }
.rk-lightbox__close {
  position: absolute;
  top: 18px;
  right: 20px;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: none;
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  font-size: 26px;
  line-height: 1;
  cursor: pointer;
}
.rk-lightbox__close:hover { background: rgba(255, 255, 255, 0.22); }
.rk-lightbox__stage {
  width: min(92vw, 900px);
  height: min(86vh, 900px);
  overflow: hidden;
  cursor: zoom-in;
  position: relative;
}
/* Handoff: the actual hover-zoom -- transform-origin is set live in
   JS to track the cursor position (see the mousemove handler), and
   this scale is what makes that origin point visibly magnify.
   transform (not width/height) so this stays GPU-composited and
   doesn't re-trigger layout on every mouse-move tick. */
.rk-lightbox__img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  transform: scale(1);
  transition: transform 120ms ease-out;
  will-change: transform;
}
.rk-lightbox__stage.is-zoomed .rk-lightbox__img { transform: scale(2.2); transition: none; }

.rk-productpage__info { padding: 6px 16px 0; }
.rk-productpage__brand {
  font-size: 11px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 4px;
}
.rk-productpage__title { font-size: 19px; font-weight: 500; margin: 0 0 4px; color: var(--ink); }
/* DISPATCH-18 §3b -- real, live sibling count ("5 colors available"),
   empty/collapsed via :empty when there's nothing to count (see
   product.html's renderVariantCounter). */
.rk-productpage__variantcount { font-size: 12px; color: var(--ink-soft); margin: 0 0 8px; }
.rk-productpage__variantcount:empty { display: none; }

/* Real: product name/price text renders in the brand accent color
   (reference §1 -- accent used on "product name/price text"). */
.rk-productpage__price { font-size: 18px; font-weight: 600; color: var(--accent); margin: 0 0 10px; }
.rk-productpage__price s { color: var(--ink-mute); font-weight: 400; margin-right: 8px; }

/* Real "In Stock" badge -- accent-colored, per reference §1. */
.rk-stockbadge {
  display: inline-block;
  font-size: 11px;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--accent);
  border: 1px solid var(--accent);
  padding: 3px 10px;
  border-radius: 2px;
  margin-bottom: 16px;
}
.rk-stockbadge--out { color: var(--ink-mute); border-color: var(--hairline); }

.rk-productpage__section-label {
  font-size: 12px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin: 0 0 10px;
}

/* DISPATCH-20 §3b -- real, final, confirmed spec from Ali: replaces
   the old color_hex-filled-circle / color_name-chip rendering
   entirely (a "variant" here is often a richly patterned,
   multi-colored version of the same design, genuinely impossible to
   represent with a single color swatch -- Ali explicitly rejected
   both a swatch and a photo-thumbnail-as-selector approach). Plain
   text-label buttons, one per sibling, showing that sibling's real
   variant_code (e.g. "23-7"). Selected state is a border/text-color
   highlight, NOT a filled background -- confirmed in real browser
   testing against a seeded 6-variant patterned product. The old
   .rk-swatch* rules (circular color fill, fallback chip) are removed
   outright, not left parked -- unlike §3a's craft block, there's no
   "will come back later" scenario here; this replaces a wrong pattern
   with the confirmed-correct one. */
.rk-variantcodes { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 22px; }
/* Handoff -- real bug fix / direct reversal, confirmed directly with
   Ali: mini real photos instead of plain variant_code number/text
   buttons -- see renderSwatches's own docstring (product.html) for
   the full history. Sized like a real small product thumbnail (not a
   tiny color dot), since the photo itself IS the label now, not a
   decoration next to one. */
.rk-variantcode {
  width: 52px;
  height: 66px;
  padding: 0;
  box-sizing: border-box;
  background: none;
  border: 1px solid var(--hairline);
  border-radius: 2px;
  cursor: pointer;
  overflow: hidden;
  flex-shrink: 0;
}
.rk-variantcode img, .rk-variantcode svg { width: 100%; height: 100%; object-fit: cover; display: block; }
.rk-variantcode.is-active { border-color: var(--accent); border-width: 2px; }
/* Handoff -- real, explicit request, confirmed directly with Ali:
   the selected variant's own real code/name as real text under the
   swatches, updating live on selection. */
.rk-productpage__selectedvariant { margin-top: 8px; font-size: 12px; letter-spacing: 0.5px; color: var(--ink-soft); text-transform: uppercase; }

.rk-productpage__qtyrow { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.rk-productpage__qtyrow input {
  width: 64px;
  border: 1px solid var(--hairline);
  padding: 9px;
  font-size: 14px;
  text-align: center;
}

.rk-productpage__actions { display: flex; gap: 10px; margin-bottom: 26px; }
.rk-btn-addcart {
  flex: 1;
  border: none;
  background: var(--btn-dark);
  color: #fff;
  padding: 14px;
  font-size: 13px;
  letter-spacing: 1px;
  text-transform: uppercase;
}
.rk-btn-addcart:hover { background: var(--btn-dark-hover); }
.rk-btn-addcart:disabled { background: var(--hairline); color: var(--ink-mute); cursor: not-allowed; }
.rk-btn-share {
  width: 48px;
  border: 1px solid var(--hairline);
  background: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
}
.rk-btn-share svg { width: 18px; height: 18px; stroke: var(--ink); }

/* Real product descriptions (reference §9 item 5 -- was confirmed
   empty on every product on the old site; this is the fix, not a
   fallback for existing gaps). Omitted entirely when a product
   genuinely has none, rather than showing an empty labeled section. */
.rk-productpage__description {
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink-soft);
  padding-top: 18px;
  border-top: 1px solid var(--hairline);
  white-space: pre-line;
}

@media (min-width: 700px) {
  .rk-productpage { max-width: 1040px; padding: 32px 24px 80px; }
  .rk-productpage__layout { display: flex; gap: 40px; align-items: flex-start; }
  .rk-productpage__gallery { flex: 1 1 55%; margin-bottom: 0; }
  .rk-productpage__info { flex: 1 1 45%; padding: 0; }
  /* Handoff: real bug found and fixed -- this forced the gallery box
     into a literal square at desktop width, on top of the base
     aspect-ratio: 4/5 above, confirmed as exactly the "square view"
     Ali described (he views/tests this on desktop). Removed rather
     than widened, so desktop now matches the same 4/5 shape as
     mobile -- one real, consistent aspect-ratio everywhere, not two
     different shapes at two breakpoints. */
}

/* Sticky add-to-bag bar (Part B convention) -- slides up from the
   bottom once the real button scrolls out of view (app.js's
   initStickyAddBar). Translate + opacity, not display:none/block, so
   it can actually transition rather than snapping in. */
.rk-stickyadd {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 39; /* under the nav/cart panels (46) and header (40) */
  display: flex;
  align-items: center;
  gap: 14px;
  background: #fff;
  border-top: 1px solid var(--hairline);
  padding: 12px 16px;
  transform: translateY(100%);
  opacity: 0;
  transition: transform 260ms ease-out, opacity 260ms ease-out;
  pointer-events: none;
}
.rk-stickyadd.is-visible { transform: translateY(0); opacity: 1; pointer-events: auto; }
.rk-stickyadd__info { flex: 1; min-width: 0; }
.rk-stickyadd__name {
  margin: 0;
  font-size: 13px;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rk-stickyadd__price { margin: 2px 0 0; font-size: 13px; font-weight: 600; color: var(--accent); }
.rk-stickyadd__price s { color: var(--ink-mute); font-weight: 400; margin-right: 6px; }
.rk-stickyadd .rk-btn-addcart { flex: 0 0 auto; width: auto; padding: 12px 22px; }

/* ---------------------------------------------------------------- */
/* Filter form (kept functional, styled as a slide-down disclosure) */
/* ---------------------------------------------------------------- */

/* ---------------------------------------------------------------- */
/* Generic form pages (login / register / account / checkout)        */
/* ---------------------------------------------------------------- */

.rk-formpage { max-width: 420px; margin: 0 auto; padding: 40px 24px 60px; }
.rk-formpage__title {
  font-size: 15px;
  letter-spacing: 3px;
  text-transform: uppercase;
  font-weight: 700;
  margin: 0 0 30px;
}
.rk-field { margin-bottom: 26px; }
.rk-field label {
  display: block;
  font-size: 12px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 8px;
}
.rk-field input, .rk-field select {
  width: 100%;
  border: none;
  border-bottom: 1px solid var(--ink);
  padding: 6px 0;
  font-size: 16px;
  font-family: inherit;
  color: var(--ink);
  outline: none;
  background: transparent;
}
.rk-field--boxed input, .rk-field--boxed select {
  border: 1px solid var(--hairline);
  padding: 10px 12px;
}
.rk-forgot { display: block; margin: -10px 0 22px; font-size: 14px; }
.rk-formpage .rk-btn { margin-top: 4px; }
.rk-formpage__divider {
  text-align: center;
  color: var(--ink-soft);
  font-size: 12px;
  letter-spacing: 2px;
  margin: 26px 0;
}
.rk-formpage__section-title {
  font-size: 13px;
  letter-spacing: 2px;
  text-transform: uppercase;
  font-weight: 700;
  margin: 0 0 12px;
}
.rk-formpage__note { font-size: 13px; color: var(--ink-soft); line-height: 1.6; }

.rk-error {
  background: #fbeceb;
  color: var(--danger);
  border: 1px solid #f1cfcb;
  padding: 10px 14px;
  font-size: 14px;
  margin-bottom: 18px;
  border-radius: 2px;
}
/* Real, reusable "this specific field has a problem" marker -- same
   real pattern/class name as admin_frontend and pos_backend, applied
   via the same markFieldError/clearFieldErrors helpers in app.js. */
.field-error {
  border-color: var(--danger) !important;
  box-shadow: 0 0 0 1px var(--danger);
}

/* ---------------------------------------------------------------- */
/* Simple list pages (cart full page / orders) reuse table look but  */
/* restyled to match the rest of the site                            */
/* ---------------------------------------------------------------- */

.rk-simple-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
  margin: 20px 0;
}
.rk-simple-table th {
  text-align: left;
  font-size: 11px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--ink-soft);
  border-bottom: 1px solid var(--ink);
  padding: 10px 8px;
}
.rk-simple-table td {
  padding: 12px 8px;
  border-bottom: 1px solid var(--hairline);
  vertical-align: middle;
}
.rk-simple-table input[type="number"] {
  width: 3.5em;
  padding: 4px;
  border: 1px solid var(--hairline);
}
.rk-simple-table button {
  border: 1px solid var(--btn-dark);
  background: #fff;
  color: var(--btn-dark);
  padding: 6px 10px;
  font-size: 12px;
}

.rk-page { max-width: 640px; margin: 0 auto; padding: 30px 20px 60px; }
.rk-page__title {
  font-size: 15px;
  letter-spacing: 3px;
  text-transform: uppercase;
  font-weight: 700;
  margin: 0 0 6px;
}
.rk-subtotal-row {
  display: flex;
  justify-content: space-between;
  font-weight: 700;
  padding: 14px 8px;
  border-top: 2px solid var(--ink);
}
.rk-empty-note { color: var(--ink-soft); padding: 30px 0; text-align: center; }

/* ---------------------------------------------------------------- */
/* Checkout (DISPATCH-11 §3c) -- tabbed Details/Shipping/Payment/    */
/* Review flow, matching Ali's own reference screenshots of the real */
/* old site's flow precisely (mint = active step, peach = completed  */
/* step, matching those screenshots' own two-tone tab progression).  */
/* ---------------------------------------------------------------- */

:root {
  --checkout-mint: #d8f0e8;
  --checkout-mint-tab: #cdeee0;
  --checkout-peach: #e8cdb0;
}

.rk-checkout {
  display: flex;
  gap: 28px;
  max-width: 1000px;
  margin: 0 auto;
  padding: 30px 20px 60px;
  align-items: flex-start;
}
.rk-checkout__main { flex: 1 1 auto; min-width: 0; }

.rk-checkout__tabs {
  display: flex;
  border-bottom: 1px solid var(--hairline);
  margin-bottom: 0;
}
.rk-checkout__tab {
  flex: 1;
  text-align: center;
  padding: 14px 8px;
  font-size: 13px;
  letter-spacing: 1px;
  font-weight: 700;
  color: var(--ink-soft);
  background: #f4f2f0;
  cursor: pointer;
}
.rk-checkout__tab.is-complete { background: var(--checkout-peach); color: var(--ink); cursor: pointer; }
.rk-checkout__tab.is-active { background: var(--checkout-mint-tab); color: var(--ink); }

.rk-checkout__panel {
  background: var(--checkout-mint);
  padding: 24px;
  margin-top: 0;
}
.rk-checkout__panel h2 {
  font-size: 15px;
  letter-spacing: 1px;
  text-transform: uppercase;
  font-weight: 700;
  margin: 0 0 18px;
}
.rk-checkout__panel-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  margin-bottom: 18px;
}
.rk-checkout__panel-head h2 { margin: 0; }

.rk-checkout__radio-card {
  display: flex;
  align-items: center;
  gap: 12px;
  background: #fff;
  border: 1px solid var(--hairline);
  padding: 14px 16px;
  margin-bottom: 10px;
  cursor: pointer;
}
.rk-checkout__radio-card input { flex-shrink: 0; }
.rk-checkout__radio-title { display: block; font-weight: 600; }
.rk-checkout__radio-sub { display: block; color: var(--ink-soft); font-size: 13px; }

.rk-checkout__inline-form {
  background: #fff;
  border: 1px solid var(--hairline);
  padding: 16px;
  margin-bottom: 16px;
}
.rk-checkout__inline-form .rk-field { margin-bottom: 14px; }
.rk-checkout__inline-form-actions { display: flex; gap: 10px; }
.rk-checkout__guest-address-confirm {
  background: #fff;
  border: 1px solid var(--hairline);
  padding: 14px 16px;
  margin-bottom: 16px;
}

.rk-checkout__continue { width: 220px; }

.rk-checkout__error {
  background: #fbeceb;
  color: var(--danger);
  border: 1px solid #f1cfcb;
  padding: 10px 14px;
  font-size: 14px;
  margin-bottom: 14px;
  border-radius: 2px;
}

.rk-checkout__review-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
  margin-bottom: 24px;
}
.rk-checkout__review-grid strong {
  display: block;
  font-size: 12px;
  letter-spacing: 1px;
  text-transform: uppercase;
  margin-bottom: 8px;
}
.rk-checkout__review-grid p { margin: 0; line-height: 1.5; color: var(--ink); }

.rk-checkout__summary {
  flex: 0 0 300px;
  border: 1px solid var(--hairline);
  padding: 20px;
}
.rk-checkout__summary h2 {
  font-size: 15px;
  letter-spacing: 1px;
  text-transform: uppercase;
  font-weight: 700;
  margin: 0 0 4px;
  padding-bottom: 12px;
  border-bottom: 2px solid var(--accent);
}
.rk-checkout__summary-table { width: 100%; border-collapse: collapse; margin: 14px 0; font-size: 14px; }
.rk-checkout__summary-table th {
  text-align: left;
  font-size: 11px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--ink-soft);
  padding-bottom: 8px;
  border-bottom: 1px solid var(--hairline);
}
.rk-checkout__summary-table th:last-child, .rk-checkout__summary-table td:last-child { text-align: right; }
.rk-checkout__summary-table td { padding: 6px 0; }

.rk-checkout__summary-row {
  display: flex;
  justify-content: space-between;
  padding: 6px 0;
  font-size: 14px;
  color: var(--ink-soft);
}
/* Handoff -- real bug fix, found live while testing the new Whish fee
   row: display:flex above overrides the browser's own default
   [hidden] { display: none } rule (same class of bug as .nav-badge's
   own earlier fix elsewhere in this file) -- every other summary row
   (shipping/coupon/gift card) had this same latent bug, just masked
   because they're empty text when hidden, which looks the same as
   genuinely not being there. The new Whish fee row's own static label
   text made it actually visible. */
.rk-checkout__summary-row[hidden] { display: none; }
.rk-checkout__summary-row--total {
  font-weight: 700;
  font-size: 16px;
  color: var(--ink);
  border-top: 1px solid var(--hairline);
  margin-top: 6px;
  padding-top: 12px;
}

.rk-checkout__code-box {
  border: 1px solid var(--hairline);
  padding: 14px;
  margin-top: 16px;
}
.rk-checkout__code-box label {
  display: block;
  font-size: 12px;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 8px;
}
.rk-checkout__code-row { display: flex; gap: 8px; }
.rk-checkout__code-row input {
  flex: 1;
  border: 1px solid var(--hairline);
  padding: 8px 10px;
  font-size: 14px;
  font-family: inherit;
}
.rk-checkout__code-note { font-size: 12px; color: var(--ink-soft); margin: 8px 0 0; }

.rk-btn--sm { display: inline-block; width: auto; padding: 8px 16px; font-size: 13px; margin-bottom: 0; }

@media (max-width: 720px) {
  .rk-checkout { flex-direction: column; }
  .rk-checkout__summary { flex: 1 1 auto; width: 100%; }
  .rk-checkout__review-grid { grid-template-columns: 1fr; }
  /* Handoff -- real, explicit request, confirmed directly with Ali:
     "on mobile view, i dont want the variants cards in parent
     product view to take more than 50% of the area under the main
     image" -- the fan's own fixed 153px width (sized for a real
     desktop-width tile) could exceed half of a real, narrow mobile
     tile's own inforow, crowding out the name/price text next to it.
     max-width caps it at exactly half of whatever the real inforow's
     own width actually is on a given phone, leaving the other half
     for name/price regardless of screen size -- overriding the fixed
     153px, not replacing it (desktop keeps its own real fixed size,
     min-width:960px's own rule is untouched).

     Handoff -- real, explicit follow-up request, confirmed directly
     with Ali: "decrease the size of variant stack under a parent
     product on mobile view by 30%" -- real width/height set here,
     each exactly 70% of the base 153px/102px desktop size (107px/
     71px), so the whole stack shrinks proportionally rather than
     just getting narrower while staying just as tall (which would
     have distorted -- not shrunk -- each card's own real aspect
     ratio). The 50% max-width cap above stays on top of this as a
     real safety net for a genuinely narrow phone, not replaced by
     it -- on the narrowest screens the smaller of the two still
     wins. */
  .rk-varthumbs { max-width: 50%; width: 107px; height: 71px; }

  /* Handoff -- real bug fix, confirmed directly with Ali against his
     own real phone screenshot ("Checkout fields design is not mobile
     friendly and some text box's edge is not shown on the right
     edge"): the real root cause, confirmed live (measured the actual
     page 501px wide inside a real 375px viewport) -- .rk-checkout__
     tab's own flex:1 should have let 5 tabs share the row and shrink
     to fit, but a flex item's own real, implicit default (min-width:
     auto, not 0) stopped each one shrinking past its own longest
     unbroken word ("VERIFICATION"/"CONFIRMATION"), forcing the whole
     row -- and everything under it, since .rk-checkout__main's own
     width is driven by its own widest child -- wider than the real
     phone screen. That's the ONE real fix needed here: once the tabs
     row can genuinely shrink to fit, the input fields (already a
     real width: 100% of their own real parent) fit correctly too,
     with no accordion/redesign of the fields themselves required.
     min-width: 0 lets each tab actually shrink; smaller font + tighter
     padding + a real 2-line wrap (more readable than truncating
     "CONFIRMATION" to "CONF…") make 5 tabs legible at once in that
     narrower real space. */
  .rk-checkout__tab {
    min-width: 0;
    font-size: 9px;
    letter-spacing: 0;
    padding: 10px 3px;
    white-space: normal;
    line-height: 1.3;
    word-break: break-word;
  }
}
