/* ==========================================================================
   Kanya Creation — site.css
   Redesign 2026-09-23. Plain CSS, no build step, no framework.

   PALETTE. Sampled from kanya_logo.png — the pink hand #CF358B, the indigo
   wordmark #2E3192 — and the approved WhatsApp opt-in banner (maroon #7A1F4C).
   The 23-Sep polish pass deepened it rather than replacing it, because the brand
   is the logo and the logo did not change:

     * PAPER IS NOT WHITE. #fffcf8 is an ivory with the maroon's own warmth in it.
       White paper made every pink on it look like a sticker; ivory makes the same
       pink look printed. Cards then go to true #ffffff, so a card is lifted off
       the page by being LIGHTER than it, which costs nothing and reads as depth.
     * A REAL RAMP, not three pinks. 050 / 100 / 200 / 300 / base / 600 / 700 and
       maroon 800 / 900 / 950, so a tint is chosen from the ramp instead of being
       mixed by hand at the point of use.
     * ONE ACCENT. The logo's indigo, and only the indigo. It marks the accounts
       desk and nothing else on the site, which is exactly what makes it readable
       as "this is the other channel". WhatsApp green stays functional — green on
       this site always means "this opens WhatsApp" — and marigold is seasonal.
     * ON-DARK INK IS ITS OWN SCALE. The maroon bands, the announce bar and the
       footer are dark in BOTH themes, so their text colours live in --deep-* and
       do not flip with the theme. Getting that wrong is what previously put a
       3.27:1 pink on the footer of all eight pages.

   Every pair below is measured, in light, in dark and under the Navratri skin;
   the numbers are in docs/website_2026-09-23/B_redesign.md. Nothing here is under
   4.5:1 for body text or 3:1 for large text.
   ========================================================================== */

/* ---------------------------------------------------------------- tokens */
:root {
  color-scheme: light;

  /* brand — pink ramp */
  --pink-050:    #fdeff6;
  --pink-100:    #fadceb;
  --pink-200:    #f4b8d8;
  --pink-300:    #f2a2c9;     /* ON-DARK role — see --deep-* below */
  --pink-400:    #e35da4;
  --pink:        #cf358b;
  --pink-600:    #b2246f;
  --pink-700:    #8e1a58;
  /* brand — maroon ramp */
  --maroon:      #7a1f4c;
  --maroon-800:  #5c1639;
  --maroon-900:  #40102a;
  --maroon-950:  #2a0a1c;
  /* the one accent: the logo's own indigo. Reserved for the accounts channel. */
  --accent:      #2e3192;
  --accent-ink:  #2a2d86;     /* accent text on paper */
  --accent-lit:  #aeb1f2;     /* accent text on the maroon bands */
  --accent-soft: rgba(46, 49, 146, 0.07);
  --indigo:      var(--accent);   /* kept: the contact page's accounts panel uses it */
  --wa:          #25d366;
  --wa-ink:      #0b5c3a;

  /* surfaces + text */
  --paper:       #fffcf8;
  --paper-2:     #fdf5ef;
  --surface:     #ffffff;
  --surface-2:   #fbf0f5;
  --blush:       #fdf1f6;
  --ink:         #23131d;
  --ink-2:       #4c3441;
  --muted:       #6b5260;
  --line:        rgba(64, 16, 42, 0.13);
  --line-strong: rgba(64, 16, 42, 0.26);

  /* ON-DARK ink. The announce bar, the .section--deep bands and the footer are the
     same near-black maroon in both themes, so these four do NOT flip with the theme
     and are declared once, here. */
  --deep-ink:    #fbeff5;     /* 16.2:1 on --maroon-950 */
  --deep-ink-2:  #efd8e5;     /* 13.5:1 — lede and running copy */
  --deep-muted:  #cfa8bd;     /*  8.6:1 — notes under a line */
  --deep-quiet:  #b892a4;     /*  6.6:1 — the registration line, the quietest type */
  --deep-line:   rgba(255, 246, 250, 0.16);

  --shadow-sm:   0 1px 2px rgba(42, 10, 28, 0.06), 0 2px 8px rgba(42, 10, 28, 0.05);
  --shadow-md:   0 2px 6px rgba(42, 10, 28, 0.07), 0 12px 32px rgba(42, 10, 28, 0.10);
  --shadow-lg:   0 4px 12px rgba(42, 10, 28, 0.10), 0 24px 60px rgba(42, 10, 28, 0.16);

  /* type */
  --font-display: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua",
                  Georgia, "Noto Serif", "Times New Roman", serif;
  --font-ui: system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans",
             "Helvetica Neue", Arial, sans-serif;

  --step--1: clamp(0.82rem, 0.79rem + 0.13vw, 0.875rem);
  --step-0:  clamp(1rem, 0.97rem + 0.16vw, 1.0625rem);
  --step-1:  clamp(1.125rem, 1.07rem + 0.28vw, 1.3125rem);
  --step-2:  clamp(1.35rem, 1.24rem + 0.53vw, 1.7rem);
  --step-3:  clamp(1.62rem, 1.42rem + 0.98vw, 2.25rem);
  --step-4:  clamp(1.95rem, 1.6rem + 1.75vw, 2.85rem);
  /* Display size is capped lower than before: at 3.3rem a 40-character headline still
     sets in three lines inside the hero column instead of nine. Measure beats scale. */
  --step-5:  clamp(2.15rem, 1.65rem + 2.4vw, 3.3rem);

  /* measure — the only two text widths on the site */
  --measure: 66ch;          /* body copy: lands at 60-75 characters everywhere */
  --measure-display: 19ch;  /* headlines: forces a 2-4 line rag, never a word ladder */

  /* layout */
  --wrap: 1180px;
  --wrap-narrow: 760px;
  --gutter: clamp(1rem, 0.6rem + 2vw, 2.5rem);
  --radius-sm: 8px;
  --radius: 14px;
  --radius-lg: 22px;
  /* One height, always. The logo needs 52px plus its clear space; the bar does not
     shrink on scroll, so scroll-padding-top and the mobile panel's offset are both
     simply this number and can never disagree with what is on screen. */
  --header-h: 76px;

  /* vertical rhythm — every block gap on the site is one of these five, so nothing
     is ever an arbitrary number typed into a style attribute. */
  --space-2xs: 0.5rem;
  --space-xs:  0.75rem;
  --space-s:   1.1rem;
  --space-m:   1.75rem;
  --space-l:   2.5rem;
  --space-xl:  clamp(3rem, 2rem + 5vw, 6.5rem);

  /* the tone an image sits on before it has decoded */
  --skeleton:   #f6e6ee;
  --skeleton-2: #fbf0f5;

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --dur: 320ms;
  --dur-slow: 620ms;
}

:root[data-theme="dark"] {
  color-scheme: dark;
  /* The ramp inverts in ROLE, not in hue: 050 is still the quietest tint and 700 is
     still the text pink, they have simply swapped ends of the lightness scale. Code
     that says var(--pink-700) for a link therefore keeps meaning "link" in both. */
  --pink-050:    #2d1422;
  --pink-100:    #3a1a2c;
  --pink-200:    #4d2338;
  /* --pink-300 is an ON-DARK role and does NOT flip: it is only ever used on the
     maroon bands and the footer, which are dark in both themes. The old dark value
     (#b8256f) darkened it against an already-dark ground and measured 3.27:1. */
  --pink-300:    #f2a2c9;
  --pink-400:    #ef7fb8;
  --pink:        #f072b4;
  --pink-600:    #f58cc2;
  --pink-700:    #f9a6d0;
  --maroon:      #b34578;
  --maroon-800:  #3a0f26;
  --maroon-900:  #260b18;
  --maroon-950:  #1b0710;
  --accent:      #a3a6ef;
  --accent-ink:  #aeb1f2;
  --accent-soft: rgba(163, 166, 239, 0.10);

  /* Neutrals are not grey: every one of them carries a little of the maroon, so the
     dark theme reads as this brand at night rather than as a stock dark mode. */
  --paper:       #170d13;
  --paper-2:     #1d1118;
  --surface:     #221520;
  --surface-2:   #2b1a27;
  --blush:       #1d1118;
  --ink:         #f9eff4;
  --ink-2:       #e0cbd6;
  --muted:       #b9a2b0;
  --line:        rgba(255, 240, 247, 0.12);
  --line-strong: rgba(255, 240, 247, 0.24);
  /* Dark mode is authored, not inverted: the lift between surfaces comes from a warm
     rising tint (the maroon in the logo), and shadow is joined by a 1px top highlight
     so a raised card reads as raised rather than as a darker hole. */
  --shadow-sm:   0 1px 2px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 233, 244, 0.045);
  --shadow-md:   0 2px 6px rgba(0, 0, 0, 0.45), 0 12px 32px rgba(0, 0, 0, 0.45),
                 inset 0 1px 0 rgba(255, 233, 244, 0.06);
  --shadow-lg:   0 4px 12px rgba(0, 0, 0, 0.5), 0 24px 60px rgba(0, 0, 0, 0.55),
                 inset 0 1px 0 rgba(255, 233, 244, 0.07);

  --skeleton:   #2b1a27;
  --skeleton-2: #38222f;
}

/* Follow the system when the visitor has never touched the toggle. The inline head
   script writes data-theme before first paint, so this is the belt to that braces. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) { color-scheme: dark; }
}

/* ---------------------------------------------------------------- seasons
   A seasonal layer sits ON TOP of the brand, never in place of it. Navratri gets a warm
   marigold accent beside the logo's pink and maroon, a bandhani-dot texture and warmer
   light on the hero — and not one point of contrast, one kilobyte of image or one line of
   the layout changes to get it.

   The motif is a bandhani field: tied-and-dyed dots, which is what bandhani IS, drawn as
   two offset radial-gradients. No SVG, no data URI, no request, a few hundred bytes.

   `data-season` is set on <html> by the head script from the visitor's own date. With
   JavaScript off the attribute never appears and none of this applies.

   KANYA MAKES UNSTITCHED SUITS, NOT CHANIYA CHOLIS. The festive layer dresses the
   BUYING season — counter stock, twelve sets, dispatch — and never implies garba wear.
   The copy that goes with it is in data/seasons.json and says so at the top. */
.season-only { display: none; }
:root[data-season="navratri"] .season-only--navratri { display: block; }
:root[data-season="navratri"] span.season-only--navratri { display: inline; }
:root[data-season="navratri"] .season-hide--navratri { display: none; }

:root[data-season="navratri"] {
  /* Marigold in three keys, because one marigold cannot do three jobs:
     --festive      the colour of the rule and the texture (never carries text)
     --festive-ink  the darkest of the three: text on paper, measured at 5.5:1
     --festive-lit  text on the maroon bands, measured at 5.6:1
     Picking the pretty middle value for all three is how a festive skin quietly
     drops a site from AA to AA-minus-one-element. */
  --festive:      #c47214;
  --festive-ink:  #94540a;
  --festive-lit:  #f0a93c;
  --festive-soft: rgba(224, 138, 30, 0.13);
}
:root[data-theme="dark"][data-season="navratri"] {
  --festive:      #e09a34;
  --festive-ink:  #f0a93c;
  --festive-lit:  #ffc76b;
  --festive-soft: rgba(240, 169, 60, 0.11);
}

/* The festive accent is an accent: it colours an eyebrow, a rule and a texture. Body
   text, links and buttons keep the brand colours and the contrast they were tested at.
   Selectors are scoped to :root[data-season] so they outrank the base component rules
   whatever order the file ends up in. */
:root[data-season="navratri"] .eyebrow--festive { color: var(--festive-ink); }
:root[data-season="navratri"] .section--deep .eyebrow--festive,
:root[data-season="navratri"] .announce .eyebrow--festive { color: var(--festive-lit); }
:root[data-season="navratri"] .lede--festive {
  border-left: 3px solid var(--festive);
  padding-left: 1rem;
  margin-top: var(--space-s);
}
:root[data-season="navratri"] .center .lede--festive {
  border-left: 0; border-top: 3px solid var(--festive); padding: 0.9rem 0 0;
}

:root[data-season="navratri"] .announce {
  background: linear-gradient(100deg, var(--maroon-950) 0%, #4a1226 52%, #6b1f2e 100%);
}
:root[data-season="navratri"] .announce strong { color: var(--festive-lit); }

/* Warmer light on the hero — a second, marigold glow answering the existing pink one,
   plus the bandhani field at an opacity where it is felt rather than seen. */
:root[data-season="navratri"] .hero::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background-image:
    radial-gradient(circle at 1.5px 1.5px, var(--festive-soft) 1.4px, transparent 1.5px),
    radial-gradient(circle at 11.5px 11.5px, var(--festive-soft) 1.4px, transparent 1.5px);
  background-size: 20px 20px;
  opacity: 0.85;
}
:root[data-season="navratri"] .hero::after {
  background: radial-gradient(closest-side,
    color-mix(in srgb, var(--festive-lit) 22%, transparent), transparent);
}
:root[data-season="navratri"] .section--deep {
  background-color: var(--maroon-950);
  background-image:
    radial-gradient(circle at 1.5px 1.5px, rgba(240, 169, 60, 0.07) 1.4px, transparent 1.5px),
    radial-gradient(circle at 13.5px 13.5px, rgba(240, 169, 60, 0.07) 1.4px, transparent 1.5px);
  background-size: 24px 24px;
}

/* ---------------------------------------------------------------- reset */
*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 16px);
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: var(--step-0);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-wrap: break-word;
  /* Georgia, Palatino and Iowan Old Style all default to OLDSTYLE figures, which is why
     "832" and "27,006" used to sit at four different heights in the same row. Every
     number on this site is a quantity in a table or a statistic, so they are lining and
     tabular everywhere and only opt out where a figure is set as running prose. */
  font-variant-numeric: lining-nums tabular-nums;
  font-kerning: normal;
  hanging-punctuation: first last;
}
p, .lede, li, dd, blockquote { font-variant-numeric: lining-nums proportional-nums; }

img, picture, svg, video { display: block; max-width: 100%; }
img { height: auto; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: -0.015em;
  margin: 0 0 0.5em;
  text-wrap: balance;
  font-variant-numeric: lining-nums proportional-nums;
}
/* A display line is capped by characters, not by its container, so a headline never
   turns into a word ladder in a narrow column and never runs past 40 characters in a
   wide one. `balance` then evens the rag and keeps the last line off a single word. */
h1 { font-size: var(--step-5); max-width: calc(var(--measure-display) + 6ch); }
h2 { font-size: var(--step-4); max-width: calc(var(--measure-display) + 8ch); }
.center h1, .center h2 { margin-inline: auto; }
h3 { font-size: var(--step-2); }
h4 { font-size: var(--step-1); }
/* The one place a headline is deliberately allowed to run full width. */
.h-wide { max-width: none; }
p  { margin: 0 0 1em; text-wrap: pretty; max-width: var(--measure); }
.center p { margin-inline: auto; }
p:last-child { margin-bottom: 0; }

a { color: var(--pink-700); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--pink); }

/* A two-tone ring: the pink reads on paper and on the blush bands, the outer halo of
   page colour keeps it visible when the focused thing sits on a photograph or on the
   deep maroon. One focus style, legible on every ground on the site. */
:focus-visible {
  outline: 2px solid var(--pink);
  outline-offset: 2px;
  box-shadow: 0 0 0 5px color-mix(in srgb, var(--paper) 72%, transparent);
  border-radius: 5px;
}
.section--deep :focus-visible, .site-footer :focus-visible, .announce :focus-visible {
  outline-color: var(--pink-300);
  box-shadow: 0 0 0 5px rgba(0, 0, 0, 0.55);
}

::selection { background: color-mix(in srgb, var(--pink) 30%, transparent); color: var(--ink); }
.section--deep ::selection, .site-footer ::selection {
  background: color-mix(in srgb, var(--pink-300) 40%, transparent); color: #fff;
}

/* Dark mode gets its own scrollbar, or the one piece of the window left over from the
   light theme sits there as a bright white gutter down the side of the page. */
:root[data-theme="dark"] { scrollbar-color: #4a2b3c var(--paper); }
:root[data-theme="dark"] ::-webkit-scrollbar { width: 12px; height: 12px; }
:root[data-theme="dark"] ::-webkit-scrollbar-track { background: var(--paper); }
:root[data-theme="dark"] ::-webkit-scrollbar-thumb {
  background: #4a2b3c; border-radius: 99px; border: 3px solid var(--paper);
}
:root[data-theme="dark"] ::-webkit-scrollbar-thumb:hover { background: #6b3f56; }

hr { border: 0; border-top: 1px solid var(--line); margin: var(--space-l) 0; }

/* ---------------------------------------------------------------- utilities */
.wrap { width: min(100% - (var(--gutter) * 2), var(--wrap)); margin-inline: auto; }
.wrap--narrow { width: min(100% - (var(--gutter) * 2), var(--wrap-narrow)); margin-inline: auto; }

.section { padding-block: var(--space-xl); }
.section--tight { padding-block: clamp(2.25rem, 1.6rem + 3vw, 4rem); }
.section--blush { background: var(--blush); }
.section--deep { background: var(--maroon-950); color: var(--deep-ink); }
.section--deep h2, .section--deep h3 { color: #fff; }
.section--deep .lede, .section--deep p { color: var(--deep-ink-2); }
/* Prose links on the maroon bands were inheriting the light-theme link pink (#a9256f)
   and measuring 2.29:1 against the band. On-dark ground gets the on-dark pink. */
.section--deep a:not(.btn), .section--deep .notice a { color: var(--pink-300); }
.section--deep a:not(.btn):hover { color: #fff; }

/* Two sections of the same colour used to butt together with no seam at all. A hairline
   that fades out from the gutters gives the eye a fold to rest on without drawing a box
   around anything. */
.section + .section:not(.section--blush):not(.section--deep) { position: relative; }
.section + .section:not(.section--blush):not(.section--deep)::before {
  content: ""; position: absolute; left: 50%; translate: -50% 0; top: 0;
  width: min(100% - (var(--gutter) * 2), var(--wrap)); height: 1px;
  background: linear-gradient(90deg, transparent, var(--line) 18%, var(--line) 82%, transparent);
}

/* A section header — eyebrow, headline, lede — is one object with one rhythm, instead of
   a margin typed into a style attribute at each of the sixteen places it appears. */
.section-head { margin-bottom: var(--space-l); }
.section-head > * + * { margin-top: var(--space-xs); }
.section-head .eyebrow + h1, .section-head .eyebrow + h2 { margin-top: 0; }
.section-head h1, .section-head h2 { margin-bottom: 0; }

.eyebrow {
  font-family: var(--font-ui);
  font-size: var(--step--1);
  font-weight: 650;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--pink-700);
  margin: 0 0 0.85rem;
}
.section--deep .eyebrow { color: var(--pink-300); }

.lede { font-size: var(--step-1); color: var(--ink-2); line-height: 1.58; max-width: var(--measure); }
.muted { color: var(--muted); }
.small { font-size: var(--step--1); }

.stack > * + * { margin-top: 1rem; }
.center { text-align: center; }
.center .lede, .center .eyebrow { margin-inline: auto; }

/* The five spacing steps, as classes, so the generator never writes a raw margin again. */
.mt-2xs { margin-top: var(--space-2xs); }
.mt-xs  { margin-top: var(--space-xs); }
.mt-s   { margin-top: var(--space-s); }
.mt-m   { margin-top: var(--space-m); }
.mt-l   { margin-top: var(--space-l); }

.skip-link {
  position: absolute; left: 0.5rem; top: -100px; z-index: 200;
  background: var(--maroon-900); color: #fff;
  padding: 0.7rem 1.1rem; border-radius: var(--radius-sm); font-weight: 600;
  transition: top 150ms var(--ease);
}
.skip-link:focus { top: 0.5rem; color: #fff; }

.visually-hidden {
  position: absolute !important; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}

/* ---------------------------------------------------------------- buttons */
.btn {
  --btn-bg: var(--maroon);
  --btn-fg: #fff;
  --btn-bd: var(--maroon);
  display: inline-flex; align-items: center; justify-content: center; gap: 0.6rem;
  min-height: 48px;
  padding: 0.75rem 1.4rem;
  border: 1px solid var(--btn-bd);
  border-radius: 999px;
  background: var(--btn-bg);
  color: var(--btn-fg);
  font: inherit; font-weight: 600; font-size: var(--step-0);
  line-height: 1.2;
  text-align: center; text-decoration: none;
  cursor: pointer;
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
              background-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.btn:hover { color: var(--btn-fg); transform: translateY(-2px); box-shadow: var(--shadow-md); }
.btn:active { transform: translateY(0); }

.btn--wa { --btn-bg: var(--wa); --btn-bd: var(--wa); --btn-fg: #06331f; }
:root[data-theme="dark"] .btn--wa { --btn-fg: #07241a; }
.btn--ghost {
  --btn-bg: transparent; --btn-fg: var(--ink); --btn-bd: var(--line-strong);
}
.btn--ghost:hover { --btn-bg: var(--surface-2); }
.section--deep .btn--ghost { --btn-fg: #fff; --btn-bd: rgba(255,255,255,.4); }
.section--deep .btn--ghost:hover { --btn-bg: rgba(255,255,255,.1); }
.btn--lg { min-height: 56px; padding: 0.95rem 1.9rem; font-size: var(--step-1); }
.btn--block { width: 100%; }

.btn .ico { width: 1.15em; height: 1.15em; flex: none; fill: currentColor; }

.btn-row { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: center; }
.center .btn-row { justify-content: center; }

/* ---------------------------------------------------------------- header */
.announce {
  background: var(--maroon-950);
  color: var(--deep-ink-2);
  font-size: var(--step--1);
  text-align: center;
  padding: 0.55rem var(--gutter);
}
.announce a { color: #fff; font-weight: 600; text-decoration-color: var(--pink-300); }
.announce strong { color: #fff; }

.site-header {
  position: sticky; top: 0; z-index: 90;
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: saturate(160%) blur(12px);
  border-bottom: 1px solid transparent;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
              background-color var(--dur) var(--ease);
}
@supports not (backdrop-filter: blur(1px)) { .site-header { background: var(--paper); } }
/* At the top of the page the header is part of the hero; once the page moves it becomes
   a bar — it gains its rule, a shadow and a slightly denser ground, and the logo settles
   down to its small size. Set by site.js; without JS the header is simply always the bar. */
.site-header[data-stuck="true"] {
  border-bottom-color: var(--line);
  box-shadow: 0 1px 0 var(--line), 0 8px 24px -18px rgba(46, 10, 27, 0.5);
  background: color-mix(in srgb, var(--paper) 94%, transparent);
}
:root:not(.js) .site-header { border-bottom-color: var(--line); }

/* Scroll progress: a 2px pink thread under the header. Width is driven by a CSS custom
   property that site.js writes once per frame (and by animation-timeline where the
   browser supports it, so on Chromium it never touches JS at all). */
.site-header::after {
  content: ""; position: absolute; left: 0; bottom: -1px; height: 2px;
  width: 100%; transform-origin: 0 50%; transform: scaleX(var(--scroll-progress, 0));
  background: linear-gradient(90deg, var(--pink-700), var(--pink));
  opacity: 0; transition: opacity 240ms var(--ease);
}
.site-header[data-stuck="true"]::after { opacity: 1; }
:root:not(.js) .site-header::after { display: none; }
@supports (animation-timeline: scroll()) {
  :root.js .site-header::after {
    transform: scaleX(0);
    animation: kanya-progress linear both;
    animation-timeline: scroll(root block);
  }
}
@keyframes kanya-progress { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* The bar height NEVER changes. The previous build animated min-height 68 -> 56 and
   the logo 132 -> 104 on scroll, which is a layout animation: it reflowed the header
   on every frame of the transition and shoved the page content up under it. The stuck
   state is now pure PAINT — ground, rule, shadow, progress thread — so the header
   settles instead of jumping, and there is no layout shift to measure. */
.site-header__bar {
  display: flex; align-items: center; gap: clamp(0.5rem, 0.1rem + 0.9vw, 1.1rem);
  min-height: var(--header-h);
}

/* ------------------------------------------------------------------ the logo
   The lockup is the anchor of the header, so it is sized off its MARK, not off its
   bounding box. The old file was the full 2000x1028 artwork — roughly half of it
   empty paper — scaled into a 132px box, which is why the hand ended up about 60px
   across and the whole thing read as a caption. build_brand.py trims the artwork and
   writes the crop the header actually wants, so at the same box width the mark is
   about three times the area it was.

   Clear space is real space: the padding below is the logo's own margin of protection
   and the flex gap keeps the nav out of it. */
.brand {
  display: inline-flex; align-items: center; gap: 0.75rem;
  text-decoration: none; flex: none;
  padding: 4px 10px 4px 2px; margin-left: -2px; border-radius: 12px;
  transition: background-color 200ms var(--ease);
}
.brand:hover { background: color-mix(in srgb, var(--pink-050) 70%, transparent); }
:root[data-theme="dark"] .brand:hover { background: rgba(255, 240, 247, 0.06); }
.brand__chip { display: block; }
/* Two colourways, one swapped for the other on the theme. There is no white card any
   more: the card was a sticker pasted on a dark page, and the honest fix was to draw
   the logo for a dark ground instead of building it a little white room to stand in. */
.brand__logo {
  height: 52px; width: auto; display: block;
  object-fit: contain; object-position: left center;
}
.brand__logo--dark { display: none; }
:root[data-theme="dark"] .brand__logo--light { display: none; }
:root[data-theme="dark"] .brand__logo--dark { display: block; }

/* The strapline is NOT set in the header, at any width. Measured: as two lines of 10px
   uppercase it is 190px wide, and at 1280 the bar has 1180px to hold a logo, six nav
   items, four channel icons, a CTA and the theme toggle with about 25px to spare. The
   header's job is the MARK; the strapline gets the footer, where the full lockup is
   232px wide and its own type finally reads, and it is the logo's alt text everywhere.
   Kept as a hook so the markup and the stylesheet do not disagree about it. */
.brand__tag { display: none; }
.brand__text { display: none; }

.nav { margin-left: auto; }
.nav__list {
  display: flex; align-items: center; gap: 0.25rem;
  list-style: none; margin: 0; padding: 0;
}
.nav__list a {
  display: block; padding: 0.5rem 0.68rem; border-radius: 999px;
  color: var(--ink-2); font-weight: 550; font-size: var(--step--1);
  text-decoration: none; white-space: nowrap;
  transition: background-color 180ms var(--ease), color 180ms var(--ease);
}
.nav__list a:hover { background: var(--surface-2); color: var(--ink); }
.nav__list a[aria-current="page"] { color: var(--pink-700); background: var(--pink-050); }

/* ------------------------------------------------------------------ social
   Instagram, Facebook, WhatsApp, LinkedIn — four inline SVGs, no icon font and no
   third-party request. One shape per channel, used identically in the header strip,
   inside the mobile menu and in the footer, so an icon never means two things.

   WhatsApp keeps its own green in the row: on this site green ALWAYS means "this
   opens WhatsApp", and the one icon in the row that is a channel rather than a
   profile is the one worth letting the eye find. */
.social { display: flex; align-items: center; gap: 0.15rem; list-style: none; margin: 0; padding: 0; }
.social__link {
  display: inline-flex; align-items: center; justify-content: center;
  width: 36px; height: 36px; border-radius: 50%;
  color: var(--muted); text-decoration: none;
  transition: color 180ms var(--ease), background-color 180ms var(--ease);
}
.social__ico { width: 19px; height: 19px; fill: currentColor; }
.social__link:hover { color: var(--pink-700); background: var(--pink-050); }
.social__link--whatsapp { color: var(--wa-ink); }
.social__link--whatsapp:hover {
  color: var(--wa-ink); background: color-mix(in srgb, var(--wa) 18%, transparent);
}
:root[data-theme="dark"] .social__link--whatsapp { color: #4ade9a; }
:root[data-theme="dark"] .social__link--whatsapp:hover { color: #6ff0b4; }

/* The desktop strip, separated from the nav by a hairline so it reads as a different
   kind of thing from a page link. */
.header-social { display: none; flex: none; }
.header-social::before {
  content: ""; display: block; width: 1px; height: 24px;
  background: var(--line-strong); margin-right: 0.45rem;
}
.header-social { align-items: center; }
@media (min-width: 1201px) { .header-social { display: flex; } }

/* Inside the open mobile menu. 48px targets, which is above the 44px floor, spread
   across the panel so a thumb finds them without aiming. */
.nav__foot { display: none; }
.social--panel { gap: 0.5rem; margin-bottom: 1rem; }
.social--panel .social__link {
  width: 48px; height: 48px;
  border: 1px solid var(--line); background: var(--surface);
}
.social--panel .social__ico { width: 22px; height: 22px; }

.header-actions { display: flex; align-items: center; gap: 0.5rem; flex: none; }

.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; flex: none;
  border: 1px solid var(--line); border-radius: 50%;
  background: var(--surface); color: var(--ink);
  cursor: pointer; padding: 0;
  transition: background-color 180ms var(--ease), border-color 180ms var(--ease);
}
.icon-btn:hover { background: var(--surface-2); border-color: var(--line-strong); }
.icon-btn svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }

:root[data-theme="dark"] .theme-toggle .ico-moon,
:root:not([data-theme="dark"]) .theme-toggle .ico-sun { display: none; }

/* Shipped hidden: un-hidden by CSS only when JavaScript has set .js on <html>, so it is
   never a dead control. */
.nav-toggle { display: none; }
.nav-toggle .ico-close { display: none; }
.nav-toggle[aria-expanded="true"] .ico-burger { display: none; }
.nav-toggle[aria-expanded="true"] .ico-close { display: block; }
.nav-toggle[aria-expanded="true"] { background: var(--pink-050); border-color: var(--line-strong); }

/* The one CTA in the bar. Smaller type and tighter padding than a body button: it is a
   piece of header furniture, not the page's primary action — the hero's green button and
   the floating button are both larger, and both say the same thing. */
.header-cta { display: none; }
@media (min-width: 1201px) {
  .header-cta {
    font-size: var(--step--1); padding: 0.66rem 1.05rem; min-height: 42px;
  }
}

/* The collapse point moved 980 -> 1200, and the number is measured, not taste. The full
   bar — logo, six nav items, four channel icons, the CTA and the theme toggle — needs
   1082px. A 1161px viewport only offers 1080px inside its gutters, which is a two-pixel
   overflow today and a twenty-pixel one on a machine whose system-ui runs 5% wider. At
   1201px there are about 50px of slack, which is the right amount to leave for a font
   this stylesheet does not download and therefore cannot measure in advance.

   Below it the icons and the CTA move into the menu, where there is room to give them
   48px targets, and the bar holds one line at every width down to 320. */
@media (max-width: 1200px) {
  /* The slide-down panel only exists when JavaScript is running (the .js class is set
     by the inline head script before first paint). Without JavaScript the nav stays an
     ordinary wrapped list and the hamburger is hidden, so navigation always works. */
  :root.js .nav {
    position: fixed; inset: 0 0 auto; top: 0;
    margin: 0; padding: calc(var(--header-h) + 0.75rem) var(--gutter)
                        calc(1.5rem + env(safe-area-inset-bottom));
    background: var(--paper);
    border-bottom: 1px solid var(--line);
    box-shadow: var(--shadow-lg);
    max-height: 100dvh; overflow-y: auto; overscroll-behavior: contain;
    transform: translateY(-100%);
    visibility: hidden;
    /* visibility flips instantly on open and only after the slide on close, so the
       panel never flashes and never swallows clicks while it is off-screen. */
    transition: transform var(--dur) var(--ease), visibility 0s linear var(--dur);
  }
  :root.js .nav[data-open="true"] {
    transform: translateY(0); visibility: visible;
    transition: transform var(--dur) var(--ease), visibility 0s;
  }
  /* The panel is a child of the header bar, so it paints OVER its own siblings: with
     nothing else said, the open menu covered the logo AND the button that closes it.
     The two things that must stay reachable are lifted above it. */
  :root.js .brand, :root.js .header-actions { position: relative; z-index: 2; }
  :root.js .nav-toggle { display: inline-flex; order: 3; }
  :root.js .nav__foot { display: block; }

  :root:not(.js) .nav { width: 100%; order: 4; padding-bottom: 0.6rem; }
  :root:not(.js) .site-header__bar { flex-wrap: wrap; }
  :root:not(.js) .nav__list { flex-wrap: wrap; justify-content: center; }

  /* Thumb comfort: a 52px row, a rule between rows so the target is obvious, and the
     type at full body size rather than the desktop bar's small caps. */
  .nav__list { flex-direction: column; align-items: stretch; gap: 0; }
  :root:not(.js) .nav__list { flex-direction: row; gap: 0.15rem; }
  :root.js .nav__list li + li { border-top: 1px solid var(--line); }
  :root.js .nav__list a {
    display: flex; align-items: center; min-height: 52px;
    padding: 0.7rem 0.75rem; border-radius: var(--radius-sm);
    font-size: var(--step-1); font-weight: 600;
  }
  :root.js .nav__list a[aria-current="page"] { background: var(--pink-050); }
  .nav__foot { margin-top: 1.4rem; padding-top: 1.2rem; border-top: 1px solid var(--line-strong); }
  .nav__foot-label {
    margin: 0 0 0.6rem; font-size: var(--step--1); font-weight: 650;
    letter-spacing: 0.12em; text-transform: uppercase; color: var(--muted);
  }
  .header-actions { margin-left: auto; }
}
/* The scrim. It belongs to the BODY, not to the panel: the panel scrolls its own
   overflow, so a scrim drawn inside it would be clipped and would scroll away. z-index
   89 puts it under the header (90) and over everything else, and it disappears with the
   same attribute that opened the menu, so there is no state to clean up separately. */
body[data-nav="open"]::before {
  content: ""; position: fixed; inset: 0; z-index: 89;
  background: rgba(42, 10, 28, 0.5);
  animation: kanya-fade 240ms var(--ease) both;
}
@keyframes kanya-fade { from { opacity: 0; } to { opacity: 1; } }

@media (min-width: 1201px) {
  .header-cta { display: inline-flex; }
  .nav { visibility: visible !important; transform: none !important; }
  .nav__foot { display: none !important; }
}
/* 375px and below: the mark holds, everything else gives way. */
@media (max-width: 430px) { .brand__logo { height: 44px; } }
@media (max-width: 340px) { .brand__logo { height: 38px; } }

body[data-nav="open"] { overflow: hidden; }

/* ---------------------------------------------------------------- hero */
.hero { position: relative; overflow: hidden; background: var(--blush); }
.hero::after {
  content: ""; position: absolute; inset: auto -10% -40% 40%;
  height: 70%; border-radius: 50%;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--pink) 16%, transparent), transparent);
  pointer-events: none;
}
.hero__grid {
  display: grid; gap: clamp(1.75rem, 1rem + 4vw, 4rem);
  align-items: center;
  padding-block: clamp(2.5rem, 1.5rem + 5vw, 5.5rem) clamp(3.5rem, 2rem + 6vw, 7rem);
  position: relative; z-index: 1;
}
/* Two columns only once the text column can actually hold a line of text. At the old
   900px breakpoint the copy column was 415px — a 43-character measure and a nine-line
   headline. At 1040px it is 520px and the lede lands at 62 characters. */
@media (min-width: 1040px) { .hero__grid { grid-template-columns: 1.08fr 0.92fr; } }
/* At the widest the wrap is capped at 1180px, so the copy column stops growing and the
   lede settles at 59 characters. A slightly greedier split puts it back inside 60-75. */
@media (min-width: 1400px) { .hero__grid { grid-template-columns: 1.16fr 0.84fr; } }

.hero h1 { margin-bottom: 0.45em; }
.hero h1 em { font-style: normal; color: var(--pink-700); }

/* Four facts, four columns, one baseline. The old flex row wrapped 3 + 1 and dropped
   "Since 2013" onto its own line at the width where the hero is widest. */
.hero__facts {
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-s) var(--space-m);
  margin: var(--space-m) 0 0; padding: var(--space-s) 0 0;
  border-top: 1px solid var(--line);
  list-style: none;
}
@media (min-width: 560px) { .hero__facts { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.hero__facts li { font-size: var(--step--1); color: var(--muted); line-height: 1.35; }
.hero__facts b {
  display: block; font-family: var(--font-display); font-size: var(--step-2);
  color: var(--ink); font-weight: 600; line-height: 1.1;
  margin-bottom: 0.25rem;
  font-variant-numeric: lining-nums tabular-nums;
  letter-spacing: -0.01em;
}

.hero__media { position: relative; }
.hero__media .frame { margin: 0; }
.hero__media .frame:nth-child(2) {
  position: absolute; right: -4%; bottom: -14%;
  width: 44%; box-shadow: var(--shadow-lg);
}
@media (max-width: 1039px) {
  .hero__media { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; align-items: start; }
  .hero__media .frame:nth-child(2) { position: static; width: auto; margin-top: 2.5rem; }
}

/* The drape: the hero fabric breathes — a very slow, very small scale-and-drift, the
   pace of cloth settling rather than a slideshow. It runs on the compositor (transform
   only), it is the only looping animation on the site, and it stops dead under
   prefers-reduced-motion. */
.hero__media .frame:first-child img {
  animation: kanya-drape 38s var(--ease) infinite alternate;
  transform-origin: 52% 42%;
  will-change: transform;
}
@keyframes kanya-drape {
  from { transform: scale(1.035) translate3d(-0.6%, -0.4%, 0); }
  to   { transform: scale(1.085) translate3d(0.8%, 0.9%, 0); }
}

/* The inset frame drifts against the page as you scroll — scroll-driven where the
   browser has it, and simply static everywhere else. No JS, no scroll listener. */
@supports (animation-timeline: view()) {
  @media (min-width: 1040px) {
    .hero__media .frame:nth-child(2) {
      animation: kanya-drift linear both;
      animation-timeline: view(block);
      animation-range: entry 0% exit 100%;
    }
    @keyframes kanya-drift {
      from { transform: translate3d(0, 5%, 0); }
      to   { transform: translate3d(0, -9%, 0); }
    }
  }
}

.frame {
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--skeleton);
  box-shadow: var(--shadow-md);
  border: 1px solid var(--line);
  margin: 0;
  position: relative;
}
.frame img { width: 100%; aspect-ratio: var(--rot-aspect, 3 / 4); object-fit: cover; }
.frame--wide { border-radius: var(--radius); }
.rot__cap {
  position: absolute; left: 0; right: 0; bottom: 0;
  /* The scrim used to start from fully transparent, so the first line of a caption could
     land on a pale part of the photograph. It now starts at 12% and reaches 88%, which
     holds white text at 4.5:1 over every photograph in the pool. */
  padding: 3rem 1.25rem 1rem;
  background: linear-gradient(to top,
    rgba(20, 6, 13, 0.88) 0%, rgba(20, 6, 13, 0.74) 38%, rgba(20, 6, 13, 0.12) 82%, transparent 100%);
  color: #fff; font-size: var(--step--1); line-height: 1.45;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.55);
}

/* ---------------------------------------------------------------- image loading
   Nothing on this site pops in from white. Every image sits on a warm blush ground that
   breathes until the file has decoded, then the photograph crossfades over it. The
   shimmer lives on the CONTAINER, never on the <img>, so if JavaScript never runs the
   photograph is simply opaque on top of it and the visitor sees no difference. */
.frame, .design__media, .cat-card__media, .band__media, .catwalk__item {
  background-color: var(--skeleton);
  background-image: linear-gradient(105deg,
    var(--skeleton) 30%, var(--skeleton-2) 48%, var(--skeleton) 66%);
  background-size: 300% 100%;
  animation: kanya-shimmer 1.9s linear infinite;
}
@keyframes kanya-shimmer { from { background-position: 150% 0; } to { background-position: -150% 0; } }
[data-loaded] { animation: none; background-image: none; }

/* The `.imgfade` class is added by site.js as its very first statement — not by the head
   script — so an image is only ever hidden by a file that has already proved it runs and
   that is about to attach the load handler that shows it again. If site.js is missing,
   blocked or throws on parse, no image is hidden and the page is exactly as it is today. */
:root.imgfade .frame img,
:root.imgfade .design__media img,
:root.imgfade .cat-card img,
:root.imgfade .catwalk__item img,
:root.imgfade .band__media img {
  opacity: 0; transition: opacity 520ms var(--ease-out);
}
:root.imgfade img[data-loaded] { opacity: 1; }

/* Rotating slots: the inline script fills these during parse. Without JavaScript they
   stay empty and the <noscript> copy is what renders, so nothing is ever a blank box. */
picture[data-kb] img:not([src]) { display: none; }

/* ---------------------------------------------------------------- cards */
.grid { display: grid; gap: clamp(1rem, 0.7rem + 1.2vw, 1.75rem); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); }
.grid--4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 210px), 1fr)); }
/* Three cards inside a narrow measure. `grid--3`'s 260px floor only fits two of them in a
   760px column, which is how the thank-you page ended up reading 2 + 1. */
.grid--3-tight { grid-template-columns: repeat(auto-fit, minmax(min(100%, 195px), 1fr)); }

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: clamp(1.25rem, 1rem + 1vw, 1.9rem);
  box-shadow: var(--shadow-sm);
  height: 100%;
}
.card h3 { margin-bottom: 0.35em; }
.card p:last-child { margin-bottom: 0; }
.card__num {
  font-family: var(--font-display); font-size: var(--step-2);
  color: var(--pink); display: block; margin-bottom: 0.4rem; line-height: 1;
}

.cat-card {
  display: flex; flex-direction: column;
  border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; background: var(--surface);
  box-shadow: var(--shadow-sm);
  text-decoration: none; color: inherit;
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.cat-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-md); color: inherit; }
.cat-card__media { margin: 0; background: var(--surface-2); }
.cat-card img { width: 100%; aspect-ratio: var(--rot-aspect, 4 / 5); object-fit: cover; background: var(--surface-2); }
/* The card body is the flex child that grows and the "See the collection" line is pushed
   to the bottom of it, so the three CTAs sit on ONE line across the row however long each
   blurb runs. They were landing at three different heights. */
.cat-card__body { padding: 1.15rem 1.25rem 1.4rem; flex: 1; display: flex; flex-direction: column; }
.cat-card h3 { font-size: var(--step-1); margin-bottom: 0.3em; }
.cat-card p { font-size: var(--step--1); color: var(--muted); margin: 0; }
.cat-card__more {
  display: inline-block; margin-top: auto; padding-top: 0.9rem;
  font-size: var(--step--1); font-weight: 650; color: var(--pink-700);
}
.cat-card__more::after {
  content: " \2192"; display: inline-block;
  transition: transform 260ms var(--ease-out);
}
.cat-card:hover .cat-card__more::after { transform: translateX(4px); }

/* ---------------------------------------------------------------- design grid */
.filters {
  display: flex; flex-wrap: wrap; gap: 0.5rem;
  margin-bottom: var(--space-m);
  align-items: center;
}
.filters__label { font-size: var(--step--1); color: var(--muted); margin-right: 0.25rem; }
.chip {
  position: relative; overflow: hidden;
  border: 1px solid var(--line-strong); background: var(--surface);
  color: var(--ink-2); border-radius: 999px;
  padding: 0.45rem 0.95rem; min-height: 44px;
  font: inherit; font-size: var(--step--1); font-weight: 550;
  cursor: pointer;
  transition: color 200ms var(--ease), border-color 200ms var(--ease);
}
/* The pressed state is a ground that sweeps in from the left behind the label rather
   than a colour that swaps between two frames: one transform, no repaint of the label.

   The sweep must sit ABOVE the chip's own white background and BELOW its text, which is
   why the label is wrapped in a span and lifted to z-index 1. A negative z-index here
   puts the sweep behind the chip's background instead, and the pressed chip ends up
   white-on-white — which is exactly what it did before this comment was written. */
.chip::before {
  content: ""; position: absolute; inset: 0;
  background: var(--maroon); border-radius: inherit;
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform 280ms var(--ease-out);
}
.chip > span { position: relative; z-index: 1; }
.chip:hover { border-color: var(--maroon); }
.chip[aria-pressed="true"] { color: #fff; border-color: var(--maroon); }
.chip[aria-pressed="true"]::before { transform: scaleX(1); }

/* ---------------------------------------------------------------- the swatch book
   A buyer flicking through a catalogue is looking at cloth, not at product tiles. The
   cards lose their individual borders and radii and butt up against one another inside a
   single ruled block, so the grid reads as a sample book: photograph, hairline,
   photograph. The name and stock band sit UNDER the rule in small type, the way a swatch
   is captioned, instead of inside a card that competes with the picture. */
.design-grid {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  /* No gap and no gutter colour: the rules are drawn BY the cards, as a hairline shadow
     to their right and below. A row that does not fill — 19 designs in a four-column
     grid — then ends in plain paper instead of in a block of gutter colour where the
     missing cards would have been. */
  gap: 0;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
@media (min-width: 700px) { .design-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 1040px) { .design-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

.design {
  background: var(--surface);
  display: flex; flex-direction: column;
  position: relative;
  box-shadow: 1px 0 0 var(--line), 0 1px 0 var(--line);
  transition: background-color var(--dur) var(--ease);
}
.design::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  box-shadow: inset 0 0 0 0 var(--pink);
  transition: box-shadow 220ms var(--ease);
}
.design:hover { background: var(--surface-2); }
.design:hover::after, .design:focus-within::after { box-shadow: inset 0 0 0 2px var(--pink); }

.design__media { position: relative; overflow: hidden; }
.design__media img {
  width: 100%; aspect-ratio: 3 / 4; object-fit: cover;
  transition: transform 700ms var(--ease-out), opacity 520ms var(--ease-out);
}
.design:hover .design__media img { transform: scale(1.045); }
/* Un-hidden by JS only: without JS there is no dead button here. */
.design__zoom {
  position: absolute; inset: 0;
  border: 0; padding: 0; margin: 0;
  background: transparent; cursor: zoom-in;
}
.design__zoom:focus-visible { outline-offset: -5px; }
.design__body {
  padding: 0.7rem 0.8rem 0.85rem;
  display: flex; flex-direction: column; gap: 0.2rem; flex: 1;
  border-top: 1px solid var(--line);
}
.design__name {
  font-family: var(--font-display); font-size: var(--step-0); font-weight: 600;
  margin: 0; line-height: 1.2; letter-spacing: -0.005em;
  /* Two lines' worth, always: a one-line name next to a two-line one was pushing the two
     stock bands onto different baselines all the way across a row of the swatch book. */
  min-height: 2.4em;
}
.design__meta {
  font-size: 0.78rem; color: var(--muted); margin: 0;
  letter-spacing: 0.02em; font-variant-numeric: lining-nums tabular-nums;
}

.badge {
  position: absolute; left: 0.55rem; top: 0.55rem;
  display: inline-flex; align-items: center; gap: 0.35rem;
  padding: 0.28rem 0.58rem; border-radius: 999px;
  font-size: 0.7rem; font-weight: 700; letter-spacing: 0.02em;
  font-variant-numeric: lining-nums tabular-nums;
  background: rgba(255, 255, 255, 0.94); color: #3c1226;
  box-shadow: 0 1px 4px rgba(0,0,0,.18);
  backdrop-filter: blur(4px);
}
/* In dark mode a white pill is a hole punched in the photograph. The badge becomes a
   smoked glass chip instead, which is the same idea in the other key. */
:root[data-theme="dark"] .badge {
  background: rgba(22, 10, 16, 0.78); color: #ffe6f2;
  box-shadow: 0 1px 4px rgba(0,0,0,.5), inset 0 0 0 1px rgba(255,255,255,.14);
}
.badge::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: #128c47; }
:root[data-theme="dark"] .badge::before { background: var(--wa); }
.badge[data-state="limited"]::before { background: #b4650a; }
:root[data-theme="dark"] .badge[data-state="limited"]::before { background: #e8a33c; }
.badge[data-state="made-to-order"]::before { background: #7b6470; }

.no-results { grid-column: 1 / -1; padding: 2rem 1rem; color: var(--muted); background: var(--surface); }

/* ---------------------------------------------------------------- the catwalk
   A slow horizontal band of real design photographs. It is NOT a carousel: there are no
   dots, no arrows, nothing to operate and nothing that moves on its own timer while you
   are reading. It is one continuous track at walking pace.

   Two identical tracks sit side by side and the pair is translated by exactly -50%, so
   the loop closes on itself with no seam and no reset jump. Every photograph in it is a
   file the page has ALREADY requested for the grid below, so the band costs zero extra
   bytes and zero extra requests — the duplicate track re-uses the same URLs.

   It pauses on hover, on focus anywhere inside it, and on a real button for anyone who
   wants it still. Under prefers-reduced-motion it does not move at all and becomes an
   ordinary horizontally scrollable strip. */
.catwalk { position: relative; padding-block: clamp(1.5rem, 1rem + 2vw, 2.75rem); }
/* The clip and the edge fade live on an inner element so the pause control can sit
   OUTSIDE them — otherwise the mask fades the button itself and, on a phone where the
   control is always visible, it has to be parked on top of a photograph. */
.catwalk__viewport {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 5%, #000 95%, transparent);
}
.catwalk__track {
  display: flex; width: max-content; gap: clamp(0.6rem, 0.4rem + 0.7vw, 1rem);
  will-change: transform;
  animation: kanya-catwalk 72s linear infinite;
}
.catwalk:hover .catwalk__track,
.catwalk:focus-within .catwalk__track,
.catwalk[data-paused="true"] .catwalk__track { animation-play-state: paused; }
@keyframes kanya-catwalk { to { transform: translate3d(-50%, 0, 0); } }

.catwalk__item {
  flex: none; width: clamp(140px, 11vw + 90px, 230px);
  border-radius: var(--radius); overflow: hidden;
  border: 1px solid var(--line);
  box-shadow: var(--shadow-sm);
}
.catwalk__item img {
  width: 100%; aspect-ratio: 3 / 4; object-fit: cover;
  transition: transform 700ms var(--ease-out), opacity 520ms var(--ease-out);
}
.catwalk__item:hover img { transform: scale(1.05); }

.catwalk__pause {
  display: block; margin: 0.6rem var(--gutter) 0 auto;
  min-height: 36px; padding: 0.3rem 0.85rem; border-radius: 999px;
  border: 1px solid var(--line-strong); background: var(--surface);
  color: var(--ink-2); font: inherit; font-size: 0.78rem; font-weight: 600;
  cursor: pointer; opacity: 0; transition: opacity 200ms var(--ease);
}
.catwalk:hover .catwalk__pause, .catwalk__pause:focus-visible { opacity: 1; }
@media (hover: none) { .catwalk__pause { opacity: 1; } }

/* ---------------------------------------------------------------- full-bleed band
   One photograph, edge to edge, used as a breath between two sections of text rather
   than as decoration. It is always a real Kanya photograph. */
.band {
  position: relative; overflow: hidden;
  background: var(--maroon-950);
}
.band__media { margin: 0; }
.band__media img {
  width: 100%; height: clamp(220px, 34vw, 460px); object-fit: cover;
  object-position: center 42%;
}
@supports (animation-timeline: view()) {
  .band__media img {
    animation: kanya-band-pan linear both;
    animation-timeline: view(block);
    animation-range: entry 0% exit 100%;
  }
  @keyframes kanya-band-pan {
    from { transform: scale(1.12) translate3d(0, -2.5%, 0); }
    to   { transform: scale(1.12) translate3d(0, 2.5%, 0); }
  }
}
.band__cap {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 3.5rem var(--gutter) 1.25rem;
  background: linear-gradient(to top, rgba(20, 6, 13, 0.9), rgba(20, 6, 13, 0.55) 45%, transparent);
  color: #fff; font-size: var(--step--1);
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6);
}
.band__cap .wrap { padding: 0; }

/* ---------------------------------------------------------------- the floor film
   A one-minute landscape film of the factory. preload="none" and no autoplay: the file
   is not touched until the visitor presses play, so it costs nothing on first load and
   never starts making noise at someone in a shop. The poster is an ordinary lazy image
   and every claim the film makes is also written in the text beside it, so the section
   reads completely without ever being played. */
.film { margin: 0; position: relative; }
.film__frame {
  position: relative; border-radius: var(--radius-lg); overflow: hidden;
  background: var(--maroon-950); border: 1px solid var(--line);
  box-shadow: var(--shadow-md);
  aspect-ratio: 16 / 9;
}
.film__frame video, .film__frame img {
  width: 100%; height: 100%; object-fit: cover; display: block;
}
.film__play {
  position: absolute; inset: 0; z-index: 2;
  display: grid; place-items: center; gap: 0.6rem;
  border: 0; background: linear-gradient(to top, rgba(20, 6, 13, 0.55), rgba(20, 6, 13, 0.12));
  color: #fff; font: inherit; font-weight: 650; cursor: pointer;
  transition: background-color 240ms var(--ease);
}
.film__play:hover { background: linear-gradient(to top, rgba(20, 6, 13, 0.62), rgba(20, 6, 13, 0.22)); }
.film__play span:first-child {
  width: 68px; height: 68px; border-radius: 50%;
  background: rgba(255, 255, 255, 0.92); color: var(--maroon-900);
  display: grid; place-items: center;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.35);
  transition: transform 260ms var(--ease-out);
}
.film__play:hover span:first-child { transform: scale(1.07); }
.film__play svg { width: 26px; height: 26px; fill: currentColor; margin-left: 3px; }
.film__label { font-size: var(--step--1); text-shadow: 0 1px 3px rgba(0, 0, 0, 0.6); }
.film figcaption { margin-top: var(--space-xs); }

/* ---------------------------------------------------------------- daily designs panel */
.pitch {
  display: grid; gap: clamp(1.5rem, 1rem + 3vw, 3.5rem);
  align-items: center;
}
@media (min-width: 900px) { .pitch { grid-template-columns: 1fr 1fr; } }

.phone {
  --bezel: 10px;
  width: min(100%, 320px); margin-inline: auto;
  background: #12080e; border-radius: 34px; padding: var(--bezel);
  box-shadow: var(--shadow-lg);
  border: 1px solid rgba(255,255,255,.08);
}
.phone__screen {
  background: #ece5dd; border-radius: 26px; overflow: hidden;
  display: flex; flex-direction: column; min-height: 420px;
}
:root[data-theme="dark"] .phone__screen { background: #0b141a; }
.phone__bar {
  background: var(--maroon-900); color: #fff;
  padding: 0.7rem 0.9rem; display: flex; align-items: center; gap: 0.6rem;
}
.phone__bar span { font-size: 0.8rem; line-height: 1.2; }
.phone__bar b { display: block; font-size: 0.9rem; }
.phone__body { padding: 0.8rem; display: flex; flex-direction: column; gap: 0.5rem; }
.bubble {
  background: #fff; color: #111b21; border-radius: 10px 10px 10px 2px;
  padding: 0.6rem 0.7rem; font-size: 0.82rem; line-height: 1.45;
  box-shadow: 0 1px 1px rgba(0,0,0,.12); max-width: 95%;
}
:root[data-theme="dark"] .bubble { background: #202c33; color: #e9edef; }
.bubble--me { align-self: flex-end; background: #d9fdd3; border-radius: 10px 10px 2px 10px; }
:root[data-theme="dark"] .bubble--me { background: #005c4b; color: #e9edef; }
.bubble__strip { display: grid; grid-template-columns: repeat(3, 1fr); gap: 3px; margin: 0.35rem 0; }
.bubble__strip img { width: 100%; aspect-ratio: 3 / 4; object-fit: cover; border-radius: 4px; }
/* WhatsApp's own timestamp grey measures 4.19:1 on the outgoing bubble and 2.61:1 on the
   dark one. This is real text on the page, so it is set two steps darker/lighter than the
   app's and clears 4.5:1 on both bubble colours in both themes. */
.bubble time { display: block; font-size: 0.65rem; color: #4e5c63; text-align: right; margin-top: 0.15rem; }
:root[data-theme="dark"] .bubble time { color: #c2d1d6; }

.promise { list-style: none; margin: 1.5rem 0 0; padding: 0; display: grid; gap: 0.9rem; }
.promise li { display: flex; gap: 0.75rem; align-items: flex-start; }
.promise .ico {
  flex: none; width: 26px; height: 26px; border-radius: 50%;
  background: var(--pink-050); color: var(--pink-700);
  display: grid; place-items: center; font-size: 0.8rem; font-weight: 700;
  margin-top: 0.15rem;
}
.section--deep .promise .ico { background: rgba(255,255,255,.12); color: #fff; }
.promise b { display: block; }
.promise span { color: var(--muted); font-size: var(--step--1); }
.section--deep .promise span { color: #dbb9cb; }

/* ---------------------------------------------------------------- process */
.steps { list-style: none; margin: 0; padding: 0; display: grid; gap: clamp(1.25rem, 1rem + 1.5vw, 2.25rem); }
@media (min-width: 760px) { .steps { grid-template-columns: repeat(2, 1fr); } }
.step {
  position: relative; padding-left: 3.6rem;
}
.step__n {
  position: absolute; left: 0; top: 0;
  width: 2.6rem; height: 2.6rem; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--pink-050); color: var(--pink-700);
  font-family: var(--font-display); font-size: var(--step-1); font-weight: 600;
  border: 1px solid var(--line);
}
.step h3 { font-size: var(--step-1); margin-bottom: 0.3em; }
.step p { color: var(--muted); font-size: var(--step--1); margin: 0; }
.step ul { margin: 0.6rem 0 0; padding-left: 1.1rem; color: var(--muted); font-size: var(--step--1); }

/* ---------------------------------------------------------------- quotes */
.quote {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: clamp(1.25rem, 1rem + 1vw, 1.9rem);
  box-shadow: var(--shadow-sm); height: 100%;
  display: flex; flex-direction: column;
}
.quote blockquote { margin: 0 0 1rem; font-family: var(--font-display); font-size: var(--step-1); line-height: 1.5; }
.quote figcaption { margin-top: auto; font-size: var(--step--1); color: var(--muted); }
.quote figcaption b { display: block; color: var(--ink); font-size: var(--step-0); font-family: var(--font-ui); }

/* ---------------------------------------------------------------- tables / details */
.table-wrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius); }
table { border-collapse: collapse; width: 100%; font-size: var(--step--1); min-width: 480px; }
th, td { text-align: left; padding: 0.8rem 1rem; border-bottom: 1px solid var(--line); }
th { background: var(--surface-2); font-weight: 650; }
tr:last-child td { border-bottom: 0; }

details {
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); padding: 0 1.1rem;
}
details + details { margin-top: 0.75rem; }
summary {
  cursor: pointer; padding: 1rem 0; font-weight: 600;
  list-style: none; display: flex; justify-content: space-between; align-items: center; gap: 1rem;
}
summary::-webkit-details-marker { display: none; }
summary::after { content: "+"; font-size: 1.4rem; color: var(--pink); line-height: 1; }
details[open] summary::after { content: "\2212"; }
details > *:not(summary) { margin-bottom: 1rem; color: var(--muted); font-size: var(--step--1); }

/* ---------------------------------------------------------------- contact */
.contact-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 1rem; }
.contact-list li {
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); padding: 1.1rem 1.25rem;
}
.contact-list .label {
  display: block; font-size: var(--step--1); font-weight: 650;
  letter-spacing: 0.08em; text-transform: uppercase; color: var(--pink-700);
  margin-bottom: 0.3rem;
}
.contact-list .value { font-family: var(--font-display); font-size: var(--step-1); }
.contact-list .value a { text-decoration: none; }
.contact-list .note { display: block; font-size: var(--step--1); color: var(--muted); margin-top: 0.3rem; }

/* Two channels, two looks. The design line is the pink-and-green path the whole site uses;
   the accounts line is deliberately a different, quieter object — indigo rule, indigo
   labels, no green button anywhere in it — so a buyer with a design question can see at a
   glance that this is not their door. The two are never side-by-side lookalikes. */
.contact-block {
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: clamp(1.25rem, 1rem + 1vw, 1.9rem);
  background: var(--surface); box-shadow: var(--shadow-sm);
  height: 100%;
}
.contact-block h2 { font-size: var(--step-2); margin-bottom: 0.25em; }
.contact-block__note { font-size: var(--step--1); color: var(--muted); margin: 0 0 var(--space-s); }
.contact-block--sales { border-top: 3px solid var(--pink); }
.contact-block--accounts { border-top: 3px solid var(--indigo); background: var(--surface-2); }
.contact-block--accounts .label { color: var(--indigo); }
.contact-block--accounts .contact-list li { background: var(--surface); }
.contact-block--accounts a { color: var(--indigo); }
:root[data-theme="dark"] .contact-block--accounts a { color: var(--indigo); }
.contact-block--accounts a:hover { color: var(--ink); }
/* Inside the accounts panel the cards do not need their own outline as well. */
.contact-block .contact-list li { border-color: var(--line); }

.notice {
  border-left: 3px solid var(--pink);
  background: var(--pink-050);
  padding: 1rem 1.2rem; border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  font-size: var(--step--1); color: var(--ink-2);
}
.section--deep .notice { background: rgba(255,255,255,.07); color: var(--deep-ink-2); }

/* ---------------------------------------------------------------- footer */
/* The footer is a four-column object with four different jobs — who we are, where to
   go, who to talk to, where we are — rather than a run of link lists that happened to
   be laid out side by side. The ground carries a slow maroon gradient so the block has
   some depth rather than sitting on the page as one flat rectangle. */
.site-footer {
  background: var(--maroon-950);
  background-image: linear-gradient(175deg,
    color-mix(in srgb, var(--maroon-900) 55%, var(--maroon-950)) 0%,
    var(--maroon-950) 42%);
  color: var(--deep-ink-2);
  border-top: 1px solid var(--deep-line);
  /* the extra bottom space keeps the floating WhatsApp button from covering the last line */
  padding-block: clamp(2.75rem, 2rem + 3.5vw, 4.5rem) calc(1.5rem + env(safe-area-inset-bottom));
  padding-bottom: calc(4.5rem + env(safe-area-inset-bottom));
  font-size: var(--step--1);
}
.site-footer a { color: #fff; text-decoration: none; }
.site-footer a:hover { color: var(--pink-300); text-decoration: underline; }
.site-footer h2 {
  font-family: var(--font-ui); font-size: var(--step--1); font-weight: 650;
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--pink-300);
  margin: 0 0 0.9rem;
}
.footer__grid { display: grid; gap: 2.25rem; }
@media (min-width: 620px) { .footer__grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) {
  .footer__grid { grid-template-columns: 1.5fr 0.9fr 1.35fr 1fr; gap: 2rem 2.5rem; }
}
/* :not(.social) matters: the social row is a <ul> inside this grid, and a bare
   `.footer__grid ul { display: grid }` outranks `.social { display: flex }` on
   specificity, which quietly stacked the four channel icons into a vertical column. */
.footer__grid ul:not(.social) { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.6rem; }
.footer__grid ul.social { list-style: none; margin: 0; padding: 0; }
.footer__col { min-width: 0; }

/* Column 1 — the lockup at a size where its strapline finally reads (232px wide puts
   the strapline's cap height at about 9.6px), then the sentence, then the icons. */
.brand--footer { display: inline-block; text-decoration: none; }
.brand--footer .brand__logo { height: auto; width: 232px; max-width: 100%; }
.footer__brand p { margin: 1.1rem 0 0; max-width: 40ch; color: var(--deep-muted); }
.footer__brand .social { margin-top: 1.25rem; gap: 0.35rem; }
.footer__brand .social__link {
  width: 44px; height: 44px; color: var(--deep-ink-2);
  border: 1px solid var(--deep-line);
}
.footer__brand .social__ico { width: 20px; height: 20px; }
.footer__brand .social__link:hover {
  color: var(--maroon-950); background: var(--pink-300); border-color: var(--pink-300);
}
.footer__brand .social__link--whatsapp { color: #63e6a0; }
.footer__brand .social__link--whatsapp:hover {
  color: #06331f; background: var(--wa); border-color: var(--wa);
}

/* Column 3 — the split between the design channel and the accounts desk is the whole
   point of this column, so it is drawn: a label above every number, a note under it,
   and the accounts entry carried on the indigo rule it wears on the contact page. The
   accounts NUMBER is deliberately not here; this is a link to the one page that has it. */
.footer__contact > li { display: grid; gap: 0.15rem; }
.footer__label {
  font-size: 0.72rem; font-weight: 650; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--pink-300);
}
.footer__note { color: var(--deep-muted); font-size: 0.78rem; line-height: 1.45; }
.footer__accounts {
  border-left: 2px solid var(--accent-lit); padding-left: 0.85rem; margin-top: 0.35rem;
}
.footer__accounts .footer__label { color: var(--accent-lit); }
.footer__accounts a { color: var(--accent-lit); }
.footer__accounts a:hover { color: #fff; }

/* Column 4 */
.footer__addr { font-style: normal; color: var(--deep-muted); line-height: 1.7; }
.footer__note--map { margin: 0.6rem 0 0; }
.footer__h2--legal { margin-top: 1.75rem; }

.footer__bottom {
  margin-top: var(--space-l); padding-top: var(--space-s);
  border-top: 1px solid var(--deep-line);
  display: flex; flex-wrap: wrap; gap: 0.5rem 1.5rem; justify-content: space-between;
  align-items: baseline;
  color: var(--deep-muted);
}
/* The registration line: legal name, GSTIN, city. Deliberately the quietest type on the
   page — a buyer who is looking for it will find it, and nobody else notices it. */
.footer__reg {
  margin: 0.75rem 0 0; font-size: clamp(0.72rem, 0.7rem + 0.1vw, 0.78rem); line-height: 1.5;
  color: var(--deep-quiet); letter-spacing: 0.01em;
}

/* ---------------------------------------------------------------- floating WA */
/* The float duplicates the hero's own green button, so while the hero is on screen it is
   redundant AND it sat on top of the inset hero photograph. It now arrives only once the
   hero has gone, rising into place. Without JavaScript it is simply always there, as
   before — data-float is set by site.js. */
.wa-float {
  position: fixed; right: max(1rem, env(safe-area-inset-right)); bottom: max(1rem, env(safe-area-inset-bottom));
  z-index: 80;
  display: inline-flex; align-items: center; gap: 0.55rem;
  padding: 0.8rem 1.15rem; border-radius: 999px;
  background: var(--wa); color: #06331f; text-decoration: none;
  font-weight: 700; font-size: var(--step--1);
  box-shadow: 0 6px 24px rgba(37, 211, 102, 0.35), var(--shadow-md);
  transition: transform 380ms var(--ease-out), opacity 260ms var(--ease), box-shadow var(--dur) var(--ease);
}
:root.js .wa-float[data-float="hidden"] {
  opacity: 0; transform: translate3d(0, 130%, 0); pointer-events: none;
}
.wa-float:hover { transform: translateY(-2px); color: #06331f; }
.wa-float:focus-visible { opacity: 1; transform: none; pointer-events: auto; }
.wa-float svg { width: 22px; height: 22px; fill: currentColor; flex: none; }
@media (max-width: 560px) {
  .wa-float__text { display: none; }
  /* Thumb reach: on a phone the button is a 56px target sitting clear of the gesture bar
     on the side of the screen a right thumb rests on, not a 44px pill in the corner. */
  .wa-float {
    padding: 0; width: 56px; height: 56px; justify-content: center;
    bottom: max(1.1rem, calc(env(safe-area-inset-bottom) + 0.6rem));
  }
  .wa-float svg { width: 26px; height: 26px; }
}

/* ---------------------------------------------------------------- video
   preload="none" means nothing is fetched until the visitor presses play, so the film
   can never delay first paint. The poster is a normal lazy image. */
.videobox { margin: 0; }
.videobox video {
  width: min(100%, 320px);
  height: auto; aspect-ratio: 9 / 16;
  border-radius: var(--radius); background: #12080e;
  border: 1px solid var(--line); box-shadow: var(--shadow-md);
}
.videobox figcaption { margin-top: 0.75rem; }

/* ---------------------------------------------------------------- lightbox */
.lightbox {
  border: 0; padding: 0; background: transparent;
  max-width: min(92vw, 520px); max-height: 92vh;
  border-radius: var(--radius-lg); overflow: visible;
}
.lightbox::backdrop { background: rgba(20, 8, 15, 0.82); backdrop-filter: blur(3px); }
.lightbox__inner {
  background: var(--surface); border-radius: var(--radius-lg); overflow: hidden;
  box-shadow: var(--shadow-lg);
}
/* Opening a design should feel like picking the swatch up off the page, not like a modal
   appearing over it. site.js measures the thumbnail that was tapped and hands its offset
   and scale to these two properties, so the panel grows out of that exact card and
   settles back into it on close. If the measurement fails, both default to a plain,
   centred fade — the dialog is never dependent on the effect. */
.lightbox[data-zooming] .lightbox__inner {
  transform: translate3d(var(--zoom-x, 0), var(--zoom-y, 0), 0) scale(var(--zoom-s, 0.94));
  opacity: 0;
}
.lightbox__inner { transform-origin: center; }
.lightbox[data-zooming="settle"] .lightbox__inner {
  transform: none; opacity: 1;
  transition: transform 420ms var(--ease-out), opacity 260ms var(--ease-out);
}
.lightbox img { width: 100%; aspect-ratio: 3 / 4; object-fit: cover; background: var(--surface-2); }
.lightbox__body { padding: 1.1rem 1.25rem 1.4rem; }
.lightbox__body h3 { margin-bottom: 0.2em; }
.lightbox__close {
  position: absolute; right: -6px; top: -46px;
  background: rgba(255,255,255,.14); border: 1px solid rgba(255,255,255,.3); color: #fff;
}
.lightbox__close:hover { background: rgba(255,255,255,.26); }

/* ---------------------------------------------------------------- motion
   The rule the whole page obeys: motion may change how something ARRIVES, never whether
   it arrives. Nothing here is on a timer that the visitor has to wait out, nothing moves
   more than ~20px, and every animated property is transform or opacity so the compositor
   does the work and the main thread stays free for scrolling.

   Reveals are scroll-driven in CSS where the browser supports `animation-timeline` —
   no observer, no listener, no JavaScript in the scroll path at all. Browsers without it
   fall back to the IntersectionObserver in site.js. Browsers without EITHER never hide
   the content in the first place, because `.reveal` only becomes invisible under the
   `.js` class that site.js's own head script sets. */
.reveal { opacity: 1; transform: none; }
:root.js .reveal { opacity: 0; transform: translate3d(0, 16px, 0); }
:root.js .reveal.is-in {
  opacity: 1; transform: none;
  transition: opacity 560ms var(--ease-out), transform 560ms var(--ease-out);
}

@supports (animation-timeline: view()) {
  :root.js .reveal:not(.is-in) {
    animation: kanya-reveal linear both;
    animation-timeline: view(block);
    /* finished by the time the block is a fifth of the way up the viewport */
    animation-range: entry 8% cover 22%;
  }
  @keyframes kanya-reveal {
    from { opacity: 0; transform: translate3d(0, 16px, 0); }
    to   { opacity: 1; transform: none; }
  }
}

/* Cards in a revealed row arrive a beat apart rather than all at once. Three steps only —
   any more and the last card is late enough to feel like a loading state. */
:root.js .reveal > * { transition-delay: 0ms; }
:root.js .reveal.is-in > *:nth-child(2) { transition-delay: 70ms; }
:root.js .reveal.is-in > *:nth-child(3) { transition-delay: 140ms; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  /* The looping pieces are switched OFF rather than sped up, so they hold their first
     frame instead of snapping to their last one. */
  .catwalk__track, .hero__media .frame:first-child img, .band__media img,
  .site-header::after, .chip::before {
    animation: none !important;
    transform: none !important;
  }
  .catwalk { overflow-x: auto; -webkit-mask-image: none; mask-image: none; }
  .catwalk__track { width: auto; }
  .catwalk__pause { display: none; }
  :root.js .reveal, :root.js .reveal.is-in { opacity: 1 !important; transform: none !important; }
  .btn:hover, .design:hover, .cat-card:hover, .wa-float:hover,
  .design:hover .design__media img, .catwalk__item:hover img { transform: none; }
  .site-header[data-stuck="true"]::after { opacity: 0; }
}

/* ---------------------------------------------------------------- the sales pass
   Five small components added with docs/website_2026-09-23/D_seo_and_sales.md. Nothing here
   animates, nothing here is a new colour: every value is pulled from the ramp that Part B3
   measured, so the contrast audit in that document still holds. */

/* The per-card WhatsApp link (§4.2 #2). It is deliberately NOT a full green button: the grid
   is a swatch book and nineteen solid green slabs down it would fight the photographs and
   read as an advertisement rather than as a price enquiry. So it is a quiet bordered pill
   that fills green on hover and focus — clearly a control at rest, unmistakable in use. It
   sits in the card BODY, well clear of the zoom button that covers the media, so the two
   never compete for the same tap. */
.design__cta {
  margin-top: auto;
  display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem;
  min-height: 38px; padding: 0.35rem 0.6rem;
  border: 1px solid var(--line); border-radius: 999px;
  font-size: 0.78rem; font-weight: 700; letter-spacing: 0.01em;
  color: var(--wa-ink); text-decoration: none; background: var(--surface);
  transition: background-color var(--dur) var(--ease), border-color var(--dur) var(--ease),
              color var(--dur) var(--ease);
}
.design__cta .ico { width: 1.05em; height: 1.05em; flex: none; fill: currentColor; }
.design__cta:hover, .design__cta:focus-visible {
  background: var(--wa); border-color: var(--wa); color: var(--wa-ink);
}
:root[data-theme="dark"] .design__cta { color: var(--wa); }
:root[data-theme="dark"] .design__cta:hover,
:root[data-theme="dark"] .design__cta:focus-visible { color: #07241a; }

/* The hero's third CTA: the daily channel, demoted from the primary green button to a text
   link so that the catalogue ask is the only button competing for the first tap (§4.2 #1). */
.cta-tertiary {
  font-size: var(--step--1); font-weight: 600;
  text-underline-offset: 0.2em;
}

/* "Sirf trade ke liye" — the disqualifier near the hero (§4.2 #9). Quiet, but not small
   print: it has a job to do for the retail shopper who arrived on a fabric keyword. */
.qualifier {
  margin-top: var(--space-xs);
  font-size: var(--step--1); font-weight: 600; color: var(--ink-2);
  border-left: 3px solid var(--pink-200); padding-left: 0.7rem;
}

/* The rate box: a reason and a promise where there used to be a refusal (§4.2 #3). */
.notice--rate { font-size: var(--step-0); }
.notice--rate h3 {
  margin: 0 0 0.5rem; font-size: var(--step-0); font-family: var(--font-display);
  color: var(--ink);
}
.notice--rate p { margin: 0; color: var(--ink-2); }

/* The keyword-bearing H2 under the Hinglish H1 on designs.html (§2.6), and the one
   Devanagari line on about.html (§3.6b). Both are content, not decoration. */
.subhead {
  margin: 0.4rem auto 0; max-width: 34ch;
  font-family: var(--font-display); font-size: var(--step-1); font-weight: 600;
  line-height: 1.3; color: var(--ink-2);
}
.hi-line { margin-top: 1rem; color: var(--ink-2); font-size: var(--step-0); line-height: 1.8; }

/* ---------------------------------------------------------------- print */
@media print {
  .site-header, .announce, .wa-float, .nav, .filters, .lightbox { display: none !important; }
  body { background: #fff; color: #000; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 0.8em; }
}
