/* ==========================================================================
   Nurseri Lestari — css/catalog.css (C3, v2 31 Oct 2026: produk.html, produk-detail.html)
   The tile itself is the shared component (.rak* in css/components.css, markup from tileHTML() in js/catalog.js); this file lays
   the two pages out around it. Tokens from base.css only; nothing is redefined here. Phone first (390), then 640 / 900 / 1024.
   ========================================================================== */

/* ---- catalog head: the title and one sentence, clear of the floating header ---- */
.catalog-head { padding-block: calc(var(--header-h) + 3.5rem) var(--s-8); }
.catalog-head .lead { margin-top: var(--s-5); max-width: 38rem; }

/* ---- filters (P2, 1 Nov 2026, client): the search pill alone on the first row, the category chips on the row below, each with
   its Tabler glyph, "Semua produk" first; no divider lines. Under them the counter line in the shopkeeper's voice, the one
   "angka dari Tokopedia" note, and the quiet sort at the line's end ---- */
.catalog { padding-bottom: var(--section-y); }
.catalog-filters__row { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--s-5); align-items: start; }
.catalog-search { position: relative; }
.catalog-search__icon { position: absolute; left: 1.0625rem; top: 50%; translate: 0 -50%; color: var(--mute); pointer-events: none; }
.catalog-search .input { padding-left: 2.875rem; }
.catalog-search .input::-webkit-search-cancel-button, .catalog-search .input::-webkit-search-decoration { -webkit-appearance: none; }
.catalog-tags { display: flex; gap: .5rem; min-width: 0; overflow-x: auto; scrollbar-width: none; margin-inline: calc(-1 * var(--gutter)); padding: .25rem var(--gutter); scroll-snap-type: x proximity; scroll-padding-inline: var(--gutter); }   /* phones: one strip that scrolls sideways, the first chip snapping to the gutter */
.catalog-tags::-webkit-scrollbar { display: none; }
.catalog-tags .tag { flex: 0 0 auto; gap: .5rem; min-height: 2.75rem; padding: .5rem 1rem .5rem .8125rem; scroll-snap-align: start; white-space: nowrap; }
.catalog-tags .tag .icon { width: 1.125rem; height: 1.125rem; color: var(--mute); transition: color var(--dur-1); }   /* the glyph sits quiet until the chip is chosen */
.catalog-tags .tag .num { font-weight: 400; font-size: var(--fs-xs); color: var(--mute); }   /* a real tone, not opacity: 4.9:1 on paper (axe) */
.catalog-tags .tag.is-active .num { color: var(--sage-2); }
.catalog-tags .tag.is-active .icon { color: var(--olive-2); }   /* the one accent, on the chosen chip only */
@media (hover: hover) { .catalog-tags .tag:not(.is-active):hover .icon { color: var(--ink); } }
/* the counter line and the shop strip (F3, 1 Nov 2026, client: the tools row with its two stacked notes read odd). Two rows under
   the chips, the gaps unchanged (s-6 above, s-8 down to the rack): the count as one sentence (the number in weight 500, "· Hapus
   filter" while filtered, the Tokopedia note muted after a middle dot) with the sort at the line's end; then "Beli dari" on a quiet
   paper-2 strip (.card-flat, no border) with "Pakai lokasiku" and the one-line hint: one line from 900 px, three short lines on a
   phone (label + pills / locate / hint) */
.catalog-bar { display: grid; gap: var(--s-5); margin-block: var(--s-6) var(--s-8); }
.catalog-bar__line { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--s-3) var(--s-6); }
.catalog-count { flex: 1 1 20rem; min-width: 0; font-size: var(--fs-sm); color: var(--mute); }   /* basis 20rem: the sort shares the line from tablets up and drops under the sentence on phones */
.catalog-count__n { font-weight: 500; color: var(--ink); font-variant-numeric: tabular-nums; }
.catalog-count__clear[hidden] { display: none; }
.catalog-clear { font-size: var(--fs-sm); color: var(--ink-2); }
.catalog-sort { display: inline-flex; flex: 0 0 auto; align-items: center; gap: .625rem; }
.catalog-sort__label { font-size: var(--fs-sm); color: var(--mute); white-space: nowrap; }
.catalog-sort__field { position: relative; display: inline-block; }
.catalog-sort .select { width: auto; min-height: 2.75rem; padding: 0 2.5rem 0 1.125rem; appearance: none; cursor: pointer; font-size: var(--fs-sm); }
.catalog-sort__icon { position: absolute; right: .9375rem; top: 50%; translate: 0 -50%; width: 1rem; height: 1rem; pointer-events: none; color: var(--ink-2); }
.catalog-bar .catalog-bar__shop { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2) var(--s-4); padding: var(--s-4); }   /* two classes deep so it outranks .shop-choice's grid further down: the row, the note and the hint share the line while there is room; .card-flat gives the ground, the padding is the strip's own */
.catalog-bar .catalog-bar__shop[hidden] { display: none; }
@media (min-width: 900px) { .catalog-bar .catalog-bar__shop { padding: var(--s-4) var(--s-5); } .catalog-bar .catalog-bar__shop .shop-choice__hint { margin-left: var(--s-2); } }   /* on the one line the hint stands a step further from the controls than they stand from each other */
@media (min-width: 900px) {
  .catalog-search { max-width: 32rem; }   /* the pill does not stretch across the whole column */
  .catalog-tags { flex-wrap: wrap; overflow: visible; margin-inline: 0; padding: 0; }
}

/* ---- "Beli dari" (B2, 1 Nov 2026, client): a segmented pair picks the shop, Toko Cipete or Toko BSD, for every buy button on
   the detail page; "Pakai lokasiku" asks the browser for the position and lights the nearer shop, the note says which and how
   far (js/shop-choice.js). Light ground in the catalog toolbar, the dark glass panel on the detail page ---- */
.shop-choice { display: grid; justify-items: start; gap: var(--s-2); }   /* the row, then the hint / note as lines of their own (a line with flex-basis 100% would widen the block to the sum of everything) */
.shop-choice[hidden] { display: none; }
.shop-choice__row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2) var(--s-3); }
.shop-choice__label { font-size: var(--fs-sm); color: var(--mute); }
.shop-choice__seg { display: inline-flex; gap: var(--s-1); padding: var(--s-1); border: var(--stroke) solid var(--line); border-radius: var(--radius-pill); }
.shop-choice__seg .tag { min-height: 2.75rem; padding-inline: 1.125rem; border-color: transparent; cursor: pointer; transition: background var(--dur-2) var(--ease-out), color var(--dur-2) var(--ease-out); }   /* 44 px pills; the pressed one is the ink fill from base */
.shop-choice__seg .tag:focus-visible { border-radius: var(--radius-pill); outline-offset: 2px; }
.shop-locate { display: inline-flex; align-items: center; gap: .375rem; min-height: 2.75rem; padding: 0 .25rem; border: 0; background: none; font: inherit; font-size: var(--fs-sm); font-weight: 500; color: var(--ink-2); cursor: pointer; text-decoration: underline; text-decoration-color: var(--olive); text-decoration-thickness: 1.5px; text-underline-offset: 4px; transition: text-decoration-color var(--dur-1), opacity var(--dur-1); }
.shop-locate:hover { text-decoration-color: currentColor; }
.shop-locate[aria-busy="true"] { opacity: .6; pointer-events: none; }
.shop-locate[hidden] { display: none; }
.shop-locate .icon { width: 1.125rem; height: 1.125rem; color: var(--olive); }
.shop-choice__hint { font-size: var(--fs-xs); color: var(--mute); }
.shop-choice__note { font-size: var(--fs-sm); color: var(--ink-2); }
.shop-choice__note[hidden] { display: none; }
.on-dark .shop-choice__label, .on-dark .shop-choice__hint, .on-dark .shop-choice__note { color: var(--sage-2); }
.on-dark .shop-choice__seg { border-color: var(--line-dark); }
.on-dark .shop-choice__seg .tag[aria-pressed="true"] { background: var(--sage); color: var(--moss); border-color: var(--sage); }   /* base paints the pressed tag ink on ink, invisible on the moss band */
.on-dark .shop-locate { color: var(--sage-2); }
.on-dark .shop-locate .icon { color: var(--olive-2); }
@media (hover: hover) {
  .shop-choice__seg .tag[aria-pressed="false"]:hover { background: rgb(var(--ink-rgb) / .06); border-color: transparent; }
  .on-dark .shop-choice__seg .tag[aria-pressed="false"]:hover { background: rgb(var(--sage-rgb) / .08); border-color: transparent; }
}

/* ---- the grid: the shared tiles, 4 / 3 / 2 (components.css); gsap owns the arrival and the FLIP re-sort ---- */
.catalog-rak { position: relative; }
.catalog-rak[hidden] { display: none; }
.catalog-rak:empty { min-height: 52rem; }   /* two rows reserved until catalog.js renders them (CLS) */
.catalog-rak .is-leaving { pointer-events: none; }
@media (max-width: 639px) { .catalog-rak:empty { min-height: 40rem; } }

/* ---- empty rack ---- */
.catalog-empty { display: grid; justify-items: center; align-content: center; text-align: center; gap: var(--s-5); min-height: 24rem; padding: var(--s-10) var(--s-4) var(--s-12); }
.catalog-empty[hidden] { display: none; }
.catalog-empty__title { max-width: 22ch; }
.catalog-empty__actions { justify-content: center; }

/* ---- product detail, hero: a dark band; the product's card graphic matted in a big .photo, the glass price panel over its edge ---- */
.pd-hero { padding-block: calc(var(--header-h) + 3rem) clamp(3rem, 2rem + 4vw, 6rem); }
.crumbs ol { display: flex; flex-wrap: wrap; align-items: center; gap: 0 .625rem; font-size: var(--fs-sm); color: var(--sage-2); }
.crumbs li { display: inline-flex; align-items: center; gap: .625rem; min-width: 0; }
.crumbs li + li::before { content: "/"; color: var(--olive); }
.crumbs a { display: inline-block; padding-block: .75rem; text-decoration: underline; text-decoration-color: transparent; text-decoration-thickness: 1.5px; text-underline-offset: 4px; transition: text-decoration-color var(--dur-1), color var(--dur-1); }   /* padding: a 44 px tap target without moving the line */
.crumbs a:hover, .crumbs a:focus-visible { color: var(--sage); text-decoration-color: var(--olive); }
.crumbs [aria-current="page"] { color: var(--sage); max-width: 60vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.pd { display: grid; gap: var(--s-5); margin-top: var(--s-5); }
.pd[hidden] { display: none; }
.pd__photo { display: block; background: var(--paper-3); animation: pd-settle var(--dur-3) var(--ease-out) both; }   /* .photo (base) gives the radius-40 frame; paper-3 holds the square until the JPEG lands */
.pd__photo img { width: 100%; height: auto; aspect-ratio: 1; object-fit: cover; object-position: 50% 50%; }   /* P2 (1 Nov 2026): the whole square card, edge to edge, like the tiles; no mat, no crop, no multiply */
@keyframes pd-settle { from { opacity: 0; transform: translateY(18px); } }
html.reduced .pd__photo { animation: none; }
.pd__panel { display: grid; justify-items: start; align-content: start; gap: .5rem; padding: clamp(1.5rem, 1rem + 2vw, 2.75rem); }
.pd__title { font-size: var(--fs-h2); line-height: 1.05; }
.pd__cat { font-size: var(--fs-sm); color: var(--sage-2); min-height: 1.5rem; }
.pd__price { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1rem; margin-top: var(--s-4); min-height: clamp(2rem, 1.5rem + 1.6vw, 2.75rem); }
.pd__price .price { font-size: clamp(2rem, 1.5rem + 1.6vw, 2.75rem); line-height: 1; }
.pd__price .price-ask { display: inline-block; white-space: normal; line-height: 1.15; font-size: .74em; }   /* "Tanya harga di WhatsApp" (2 Nov 2026): one line on a 390 px phone, two lines on narrower ones rather than running out of the glass */
.pd__price .badge[hidden] { display: none; }
.pd__note { font-size: var(--fs-sm); color: var(--sage-2); }
.pd__shop { margin-top: var(--s-5); }   /* "Beli dari" sits right above the buttons it steers (B2) */
.pd__cta { display: grid; justify-self: stretch; margin-top: var(--s-3); gap: var(--s-3); }   /* three ways to buy, one column of equal pills: natural widths stacked raggedly in the narrow panel (B2) */
.pd__cta .btn { width: 100%; }
.pd__stock-note { font-size: var(--fs-sm); color: var(--sage-2); max-width: 36rem; }   /* only when the listing lives in the other shop */
.pd__stock-note[hidden] { display: none; }
@media (min-width: 900px) {
  .pd { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); align-items: center; gap: 0; margin-top: var(--s-8); }
  .pd__panel { --over: 4rem; position: relative; z-index: 1; margin-left: calc(-1 * var(--over)); padding-left: calc(var(--over) + 2rem); box-shadow: inset 0 1px 0 rgb(var(--paper-rgb) / .35); }   /* taste-skill-ignore: the glass inner highlight only; the glass sits over the photograph's edge (Plantio), the text starts past the strip, and no drop shadow smears the mat */
}
@media (min-width: 900px) and (max-width: 1199px) { .pd__panel { --over: 2.5rem; } }

/* ---- below the band (D4, 1 Nov 2026, client): the body reads the same whether the product has notes or not. Two columns from
   900 px: the notes (1.4fr) and the "Rincian." card (1fr), both starting level (the notes column takes the card's own padding
   as its top inset, so the two headings sit on one line); the card is there for every product, with the facts every product
   has, so the notes never stand beside an empty column, and a product without notes carries one honest line and the WhatsApp
   pill instead. Phones: one column, the card first. This band and the related band share one rhythm, section-y × .6 ---- */
.pd-body { padding-block: calc(var(--section-y) * .6); }
.pd-body[hidden] { display: none; }
.pd-body__grid { display: grid; gap: var(--s-8); align-items: start; }
.pd-body h2 { font-size: var(--fs-h3); }   /* the product's name is the page's big line; these two heads and the related head share one size */
.pd-about { display: grid; align-content: start; justify-items: start; gap: var(--s-6); }
.pd-about > [hidden] { display: none; }   /* the pill, the chips and the care note only when there is something to show; no gap for a hidden one */
.pd__desc { max-width: 40rem; font-size: var(--fs-lead); line-height: 1.5; color: var(--ink-2); }
.pd__tags { gap: .5rem .75rem; align-items: center; }
.pd__tags-label { font-size: var(--fs-sm); color: var(--mute); }
.pd__tags .cluster { gap: .5rem; }
.pd__tags .tag { min-height: 2.75rem; padding-inline: 1rem; }   /* 44 px chips, as in the catalog */
.pd__care { justify-self: stretch; max-width: 40rem; background: var(--paper-3); }
.pd__care-title { font-size: var(--fs-h4); margin-bottom: .5rem; }
.pd__care p { color: var(--ink-2); }
.pd-facts { display: grid; align-content: start; gap: var(--s-6); }
.pd__specs { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: .75rem 1.25rem; align-items: baseline; }
.pd__specs dt { font-size: var(--fs-sm); color: var(--mute); }
.pd__specs dd { min-width: 0; overflow-wrap: anywhere; }
.pd__specs a { display: inline-block; padding-block: .625rem; margin-block: -.625rem; text-decoration: underline; text-decoration-color: var(--olive); text-decoration-thickness: 1.5px; text-underline-offset: 4px; transition: text-decoration-color var(--dur-1); }   /* a 44 px hit area, the line unchanged */
.pd__specs a:hover { text-decoration-color: var(--ink); }
.pd__specs .icon { display: inline-block; width: 1em; height: 1em; vertical-align: -.1em; color: var(--olive); fill: var(--olive); }   /* inline: base makes every svg a block */
.pd__how { margin-top: var(--s-8); max-width: 40rem; background: var(--paper-3); }
.pd__how .pd__perks { margin-top: var(--s-3); }
.pd__perks { display: grid; gap: .75rem; }   /* the card's foot: the three ways we handle an order */
.pd__perks li { display: flex; align-items: flex-start; gap: .75rem; font-size: var(--fs-sm); color: var(--ink-2); }
.pd__perks .icon { width: 1.25rem; height: 1.25rem; margin-top: .125rem; color: var(--olive); }
.pd-missing { display: grid; justify-items: start; gap: var(--s-5); max-width: 40rem; padding-block: var(--s-8) var(--s-4); }
.pd-missing[hidden] { display: none; }
@media (max-width: 899px) { .pd-facts { order: -1; } }   /* phones and tablets: the facts first, right under the price panel */
@media (min-width: 900px) {
  .pd-body__grid { grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); gap: clamp(2.5rem, 5vw, 5rem); }
  .pd-about { padding-top: clamp(1.25rem, 2.5vw, 2rem); }   /* = the .card padding: "Tentang produk ini." and "Rincian." start on one line */
}

/* ---- related (D4): one row of the same tiles (four; three on tablets, two by two on phones) on the alternate light band,
   the band's rhythm shared with the body; the head is one line, heading + hint, with "Semua produk" at its end (on phones the
   hint and the link take the second line) ---- */
.pd-related { padding-block: calc(var(--section-y) * .6); }
.pd-related[hidden] { display: none; }
.pd-related__head { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s-2) var(--s-4); margin-bottom: var(--s-8); }
.pd-related__title { font-size: var(--fs-h3); }
.pd-related__hint { color: var(--ink-2); }   /* ink-2, not mute: 6.8:1 on the paper-3 band (axe: mute was 4.37:1) */
.pd-related__hint:empty { display: none; }
.pd-related__more { margin-left: auto; }
@media (max-width: 1023px) { .pd-related .rak-item:nth-child(n + 4) { display: none; } }
@media (max-width: 639px) { .pd-related .rak-item:nth-child(n + 4) { display: grid; } }

/* ---- phone buy bar: a floating dark glass pill with the price and the two actions; it follows you once the panel's buttons
   scroll away and hides over the footer. The moss tint is raised to .82 here because the bar floats over the light section,
   where the base .38 would leave sage text at 2:1 ---- */
.buy-bar { position: fixed; left: .75rem; right: .75rem; bottom: calc(.75rem + env(safe-area-inset-bottom, 0px)); z-index: 40; display: flex; align-items: center; gap: .5rem; padding: .625rem .625rem .625rem 1.125rem; background: rgb(var(--moss-rgb) / .82); translate: 0 calc(100% + 1.5rem); visibility: hidden; transition: translate var(--dur-2) var(--ease-out), visibility 0s linear var(--dur-2); }
.buy-bar.is-on { translate: 0 0; visibility: visible; transition-delay: 0s; }
.buy-bar__info { flex: 1 1 auto; min-width: 0; display: grid; line-height: 1.2; }
.buy-bar__name { font-weight: 500; font-size: var(--fs-xs); color: var(--sage-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.buy-bar__price { font-size: 1.125rem; white-space: nowrap; }   /* one line: "Tanya harga" is the short ask here (js/util.js priceHTML) */
.buy-bar__price .price-from { display: block; font-size: .7em; line-height: 1.1; }   /* "Mulai" on its own small line above the amount: the column is 90-120 px wide, "Mulai Rp25.000" does not fit beside the buttons */
.buy-bar .btn { flex: 0 0 auto; }   /* D4: a long product name shrank the icon pills to 22 px (flex shrinks by basis); the name truncates instead */
.buy-bar .btn-sm { min-height: 2.75rem; }
.buy-bar .btn-icon { width: 2.75rem; height: 2.75rem; }
@media (max-width: 767px) { html.buy-bar-on .wa-fab { opacity: 0; pointer-events: none; } }
@media (min-width: 768px) { .buy-bar { display: none; } }
