/*
 * Storefront design system — the approved design handoff (canvas v18,
 * aplikasi-andalan-handoff/design/source/src/theme.css) ported on top of
 * BeerCSS 5.0.3. Class names and measurements are the design's, so pages can
 * be compared with its screenshots at 1440, 820 and 390 px.
 *
 * Differences from the design file, all deliberate:
 * - Everything is scoped under `body.aa` (storefront layout only): the admin
 *   panel keeps its own look although it loads the same BeerCSS.
 * - The design switches tablet rules with a `.tab` class on the board; here
 *   they are media queries on BeerCSS's breakpoints (s ≤ 600, m 601–992,
 *   l ≥ 993). Widths the design never drew (993–1279, below 390) get fluid
 *   rules instead of the design's fixed 1312 px frame.
 * - The design markup is full of style="" attributes; the CSP forbids them,
 *   so each one became a class here (named after the element it styles).
 * - `--font-icon` is NOT set to "Material Symbols Outlined": that would
 *   download BeerCSS's full 456 KB icon font. icons.css points BeerCSS at the
 *   project's subset instead (make icons).
 * - Only what the built pages use is ported (the testimonials and status
 *   pills came with the product page); checkout and the other sections of
 *   the design file arrive with their pages.
 * - On phones every tap target is at least 44 px (the owner's decision of
 *   2026-09-28), although the design draws 32–36 px chips: see the end.
 * - The gateway's payment panel (`.snap` in the design) is never ported: the
 *   real one is Midtrans's own iframe.
 * Page-only rules live in css/page/<page>.css.
 */

/* ---------- Colour tokens: light (M3 scheme from #0078D4, primary pinned to the brand blue) ---------- */

/* The design's full scheme, so every BeerCSS component follows the brand;
   `aa-*` are the app's own roles (page, cards, footer, badges), `c-*` the
   eight category colour sets (tone 40 / container 90 / on-container 10).
   `--aa-inset` (sunken surfaces) is in theme.css: the admin panel's top bar
   draws the language toggle on it too. */
.aa.light {
  --primary: #0078d4;
  --on-primary: #ffffff;
  --primary-container: #d3e3ff;
  --on-primary-container: #001c39;
  --secondary: #545f71;
  --on-secondary: #ffffff;
  --secondary-container: #d8e3f8;
  --on-secondary-container: #111c2b;
  --tertiary: #6d5677;
  --on-tertiary: #ffffff;
  --tertiary-container: #f5d9ff;
  --on-tertiary-container: #261430;
  --error: #ba1a1a;
  --on-error: #ffffff;
  --error-container: #ffdad6;
  --on-error-container: #410002;
  --background: #fdfcff;
  --on-background: #1a1c1e;
  --surface: #faf9fd;
  --on-surface: #1a1c1e;
  --surface-variant: #dfe2eb;
  --on-surface-variant: #43474e;
  --outline: #73777f;
  --outline-variant: #c3c6cf;
  --shadow: #000000;
  --scrim: #000000;
  --inverse-surface: #3e3e3e;
  --inverse-on-surface: #f1f0f4;
  --inverse-primary: #a3c9ff;
  --surface-dim: #dad9dd;
  --surface-bright: #faf9fd;
  --surface-container-lowest: #ffffff;
  --surface-container-low: #f4f3f7;
  --surface-container: #eeedf1;
  --surface-container-high: #e8e8eb;
  --surface-container-highest: #e3e2e6;
  --active: rgb(26 28 30 / 0.1);
  --overlay: rgb(0 0 0 / 0.32);
  --elevate1: 0 1px 2px rgb(16 24 40 / 0.06), 0 1px 3px 1px rgb(16 24 40 / 0.05);
  --elevate2: 0 1px 2px rgb(16 24 40 / 0.1), 0 4px 10px 2px rgb(16 24 40 / 0.08);
  --elevate3: 0 2px 6px rgb(16 24 40 / 0.1), 0 12px 32px 6px rgb(16 24 40 / 0.12);
  /* BeerCSS's 1 px checkerboard image (data URI, allowed by img-src data:). */
  --image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4AWJiYGAQBgAAAP//ZyYa+wAAAAZJREFUAwAAIgAWeX9MsQAAAABJRU5ErkJggg==);
  --aa-page: #f4f3f7;
  --aa-raised: #ffffff;
  --aa-header: #ffffff;
  --aa-hero: #d3e3ff;
  --aa-on-hero: #001c39;
  --aa-tint: #e8effa;
  --aa-footer: #3e3e3e;
  --aa-on-footer: #f1f0f4;
  --aa-footer-muted: #c6c6ca;
  --aa-footer-link: #a3c9ff;
  --aa-footer-line: rgb(255 255 255 / 0.14);
  --aa-star: #e99b00;
  --aa-sale: #b02e00;
  --aa-on-sale: #ffffff;
  --aa-sale-container: #ffdbd1;
  --aa-on-sale-container: #3b0900;
  /* The special discount (decision 103): a red-to-orange that white text
     reads on everywhere (5.6:1 or more). */
  --aa-special-from: #c2185b;
  --aa-special-to: #bf360c;
  --aa-on-special: #ffffff;
  /* A special price written in colour on the page's own surfaces and the
     floating buy bar (decision 109): 4:1 or more on the bar's light blue. */
  --aa-special-ink: #bf360c;
  --aa-success: #3a6931;
  --aa-success-container: #bbf1aa;
  --aa-on-success-container: #002200;
  --aa-warn: #825500;
  --aa-warn-container: #ffddb4;
  --aa-on-warn-container: #291800;
  /* Premium add-ons in gold, free ones in silver (decision 144, the owner:
     "for premium we can use gold color and for free we can use silver
     color"; it replaced decision 142's amber): a metal's light, middle and
     shade for its medals' gradient, the ink drawn on it, its words and
     icons on the page (`-ink`: 4.5:1 or more on white and on the page) and
     the ring of its add-on cards. */
  --aa-gold-hi: #fff4cc;
  --aa-gold: #e8b931;
  --aa-gold-lo: #b7811a;
  --aa-on-gold: #3d2a00;
  --aa-gold-ink: #946200;
  --aa-gold-line: #e2bd5c;
  --aa-silver-hi: #ffffff;
  --aa-silver: #c9ced5;
  --aa-silver-lo: #8c949e;
  --aa-on-silver: #2b3036;
  --aa-silver-ink: #5f6873;
  --aa-silver-line: #cfd4da;
  /* Loading placeholders: the shape, and the band of light sweeping over it. */
  --aa-sk-base: var(--surface-container-high);
  --aa-sk-shine: var(--surface-container-lowest);
  --aa-mono: #1a1c1e;
  --aa-band: #3e3e3e;
  --aa-on-band: #f1f0f4;
  --aa-band-muted: #c6c6ca;
  --c-excel: #1b6b45;
  --c-excel-c: #a5f3c2;
  --c-excel-on: #002111;
  --c-sheets: #006a69;
  --c-sheets-c: #98f2f0;
  --c-sheets-on: #002020;
  --c-webapp: #0060ab;
  --c-webapp-c: #d3e3ff;
  --c-webapp-on: #001c39;
  --c-landing: #555899;
  --c-landing-c: #e1e0ff;
  --c-landing-on: #101152;
  --c-graphics: #865305;
  --c-graphics-c: #ffddba;
  --c-graphics-on: #2b1700;
  --c-video: #924b2a;
  --c-video-c: #ffdbcd;
  --c-video-on: #360f00;
  --c-audio: #8d4768;
  --c-audio-c: #ffd8e6;
  --c-audio-on: #3b0324;
  --c-bespoke: #3e3e3e;
  --c-bespoke-c: #3e3e3e;
  --c-bespoke-on: #ffffff;
  /* Digital invitations (decision 112): a muted rose, apart from audio's mauve. */
  --c-invite: #904a49;
  --c-invite-c: #ffdad8;
  --c-invite-on: #3b0809;
}

/* ---------- Colour tokens: dark ---------- */

/* Light tones of the brand on dark surfaces (M3 dark scheme); the footer and
   the dark bands go darker than the page instead of lighter. */
.aa.dark {
  --primary: #a3c9ff;
  --on-primary: #00315c;
  --primary-container: #004883;
  --on-primary-container: #d3e3ff;
  --secondary: #bcc7db;
  --on-secondary: #263141;
  --secondary-container: #3c4758;
  --on-secondary-container: #d8e3f8;
  --tertiary: #d9bde3;
  --on-tertiary: #3c2946;
  --tertiary-container: #543f5e;
  --on-tertiary-container: #f5d9ff;
  --error: #ffb4ab;
  --on-error: #690005;
  --error-container: #93000a;
  --on-error-container: #ffb4ab;
  --background: #1a1c1e;
  --on-background: #e3e2e6;
  --surface: #121316;
  --on-surface: #e3e2e6;
  --surface-variant: #43474e;
  --on-surface-variant: #c3c6cf;
  --outline: #8d9199;
  --outline-variant: #43474e;
  --shadow: #000000;
  --scrim: #000000;
  --inverse-surface: #e3e2e6;
  --inverse-on-surface: #2f3033;
  --inverse-primary: #0060ab;
  --surface-dim: #121316;
  --surface-bright: #38393c;
  --surface-container-lowest: #0d0e11;
  --surface-container-low: #1a1c1e;
  --surface-container: #1e2022;
  --surface-container-high: #292a2d;
  --surface-container-highest: #333538;
  --active: rgb(227 226 230 / 0.12);
  --overlay: rgb(0 0 0 / 0.5);
  --elevate1: 0 1px 2px rgb(0 0 0 / 0.5), 0 1px 3px 1px rgb(0 0 0 / 0.25);
  --elevate2: 0 1px 2px rgb(0 0 0 / 0.5), 0 4px 10px 2px rgb(0 0 0 / 0.35);
  --elevate3: 0 2px 6px rgb(0 0 0 / 0.5), 0 12px 32px 6px rgb(0 0 0 / 0.45);
  --image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR4AWL6//+/FAAAAP//qSv5QwAAAAZJREFUAwAJIAMaJWjIvQAAAABJRU5ErkJggg==);
  --aa-page: #121316;
  --aa-raised: #1a1c1e;
  --aa-header: #1a1c1e;
  --aa-hero: #004883;
  --aa-on-hero: #d3e3ff;
  --aa-tint: #172231;
  --aa-footer: #0d0e11;
  --aa-on-footer: #e3e2e6;
  --aa-footer-muted: #909094;
  --aa-footer-link: #a3c9ff;
  --aa-footer-line: rgb(255 255 255 / 0.1);
  --aa-star: #ffb952;
  --aa-sale: #ffb5a0;
  --aa-on-sale: #5f1500;
  --aa-sale-container: #872100;
  --aa-on-sale-container: #ffdbd1;
  --aa-special-from: #c2185b;
  --aa-special-to: #bf360c;
  --aa-on-special: #ffffff;
  /* Light orange: the light theme's ink was 1.6:1 on the bar's deep blue. */
  --aa-special-ink: #ffb59a;
  --aa-success: #9fd490;
  --aa-success-container: #22511c;
  --aa-on-success-container: #bbf1aa;
  --aa-warn: #f9bb64;
  --aa-warn-container: #633f00;
  --aa-on-warn-container: #ffddb4;
  --aa-gold-hi: #fff1c2;
  --aa-gold: #e5b43c;
  --aa-gold-lo: #9e7116;
  --aa-on-gold: #2e1f00;
  --aa-gold-ink: #f3c75a;
  --aa-gold-line: #8a6a24;
  --aa-silver-hi: #f5f7f9;
  --aa-silver: #bcc3cb;
  --aa-silver-lo: #7c858f;
  --aa-on-silver: #1e2226;
  --aa-silver-ink: #c3cad2;
  --aa-silver-line: #4f565e;
  --aa-sk-base: var(--surface-container-high);
  --aa-sk-shine: var(--surface-container-highest);
  --aa-mono: #e3e2e6;
  --aa-band: #292a2d;
  --aa-on-band: #e3e2e6;
  --aa-band-muted: #c3c6cf;
  --c-excel: #8ad7a8;
  --c-excel-c: #005231;
  --c-excel-on: #a5f3c2;
  --c-sheets: #7cd5d3;
  --c-sheets-c: #00504f;
  --c-sheets-on: #98f2f0;
  --c-webapp: #a3c9ff;
  --c-webapp-c: #004883;
  --c-webapp-on: #d3e3ff;
  --c-landing: #c0c1ff;
  --c-landing-c: #3e4080;
  --c-landing-on: #e1e0ff;
  --c-graphics: #feb967;
  --c-graphics-c: #663e00;
  --c-graphics-on: #ffddba;
  --c-video: #ffb596;
  --c-video-c: #743415;
  --c-video-on: #ffdbcd;
  --c-audio: #ffafd1;
  --c-audio-c: #713050;
  --c-audio-on: #ffd8e6;
  --c-bespoke: #e4e2e1;
  --c-bespoke-c: #e4e2e1;
  --c-bespoke-on: #1b1c1c;
  --c-invite: #ffb3b0;
  --c-invite-c: #733333;
  --c-invite-on: #ffdad8;
}

/* ---------- Base ---------- */

/* Google Sans Flex at the M3 body size (14/20); optical sizing follows the
   size (decision 134). Tabular figures everywhere: Roboto Flex had only
   those, so prices, counts and countdowns kept their columns and never
   jumped as a digit changed — Google Sans Flex draws proportional digits
   unless asked. `--font-code` is the codes' face (".code-text" below). */
.aa {
  --font: "Google Sans Flex", Roboto, "Segoe UI", system-ui, -apple-system, sans-serif;
  --font-code: Roboto, "Google Sans Flex", "Segoe UI", system-ui, -apple-system, sans-serif;
  font-family: var(--font);
  font-optical-sizing: auto;
  font-variant-numeric: tabular-nums;
  font-size: 0.875rem;
  line-height: 1.25rem;
  letter-spacing: 0.1px;
  color: var(--on-surface);
  background-color: var(--aa-page);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* BeerCSS adds margin-top: 1rem between stacked blocks; the design spaces
   everything with flex / grid `gap` instead. BeerCSS's rule is very specific
   (a :not() chain), hence the repeated class — the design's own trick. */
.aa.aa.aa.aa.aa
:is(
  address,
  article,
  blockquote,
  code,
  .field,
  fieldset,
  form,
  .grid,
  h1,
  h2,
  h3,
  h4,
  h5,
  h6,
  nav,
  ol,
  p,
  pre,
  .row,
  section,
  aside,
  table,
  .tabs,
  ul
) {
  margin-block-start: 0;
}

/* Headings, paragraphs and lists start from zero; sizes come from t-* classes. */
.aa :is(h1, h2, h3, h4, h5, h6, p, ul, ol, dl, dd, figure) {
  margin: 0;
}

/* Lists in the design are layout (menus, steps), never bullet lists. */
.aa :is(ul, ol) {
  list-style: none;
  padding: 0;
}

/* Images never overflow their box and sit on no text baseline. */
.aa img {
  display: block;
  max-width: 100%;
}

/* Form controls use the page font, not the browser's. */
.aa :is(input, select, textarea, button) {
  font-family: inherit;
}

/* Visually hidden, still read by screen readers. */
.aa .sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* Secondary text. */
.aa .muted {
  color: var(--on-surface-variant);
}

/* A link inside running text ("Sudah punya akun? Masuk", "Hubungi kami"):
   brand blue, underlined, the line thicker on hover. */
.aa .aa-link {
  display: inline;
  color: var(--primary);
  font-weight: 600;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

.aa .aa-link:hover {
  text-decoration-thickness: 2px;
}

/* The content column: 1312 px on the 1440 px design, 64 px margins below
   that (the design has no frame between 993 and 1440 px). */
.aa .aa-wrap {
  width: min(1312px, 100% - 128px);
  margin-inline: auto;
}

/* One visible focus ring everywhere (2 px brand outline, 2 px offset) —
   except text fields, whose own border is their ring (see Text fields). */
.aa :is(a, button, input, select, textarea, summary):focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* ---------- M3 type scale (Google Sans Flex) · add .emph for the M3 Expressive emphasised style ---------- */

.aa .t-dl {
  font-size: 57px;
  line-height: 64px;
  letter-spacing: -0.25px;
  font-weight: 400;
}

.aa .t-dm {
  font-size: 45px;
  line-height: 52px;
  letter-spacing: 0;
  font-weight: 400;
}

.aa .t-ds {
  font-size: 36px;
  line-height: 44px;
  letter-spacing: 0;
  font-weight: 400;
}

.aa .t-hl {
  font-size: 32px;
  line-height: 40px;
  letter-spacing: 0;
  font-weight: 400;
}

.aa .t-hm {
  font-size: 28px;
  line-height: 36px;
  letter-spacing: 0;
  font-weight: 400;
}

.aa .t-hs {
  font-size: 24px;
  line-height: 32px;
  letter-spacing: 0;
  font-weight: 400;
}

.aa .t-tl {
  font-size: 22px;
  line-height: 28px;
  letter-spacing: 0;
  font-weight: 400;
}

.aa .t-tm {
  font-size: 16px;
  line-height: 24px;
  letter-spacing: 0.1px;
  font-weight: 500;
}

.aa .t-ts {
  font-size: 14px;
  line-height: 20px;
  letter-spacing: 0.1px;
  font-weight: 500;
}

.aa .t-bl {
  font-size: 16px;
  line-height: 24px;
  letter-spacing: 0.15px;
  font-weight: 400;
}

.aa .t-bm {
  font-size: 14px;
  line-height: 20px;
  letter-spacing: 0.1px;
  font-weight: 400;
}

.aa .t-bs {
  font-size: 12px;
  line-height: 16px;
  letter-spacing: 0.1px;
  font-weight: 400;
}

.aa .t-ll {
  font-size: 14px;
  line-height: 20px;
  letter-spacing: 0.1px;
  font-weight: 500;
}

.aa .t-lm {
  font-size: 12px;
  line-height: 16px;
  letter-spacing: 0.2px;
  font-weight: 500;
}

.aa .t-ls {
  font-size: 11px;
  line-height: 16px;
  letter-spacing: 0.3px;
  font-weight: 500;
}

/* M3 Expressive emphasised weights: Google Sans Flex is variable, so any weight works. */
.aa :is(.t-dl, .t-dm, .t-ds).emph {
  font-weight: 720;
  letter-spacing: -0.5px;
}

.aa :is(.t-hl, .t-hm, .t-hs).emph {
  font-weight: 660;
  letter-spacing: -0.2px;
}

.aa :is(.t-tl, .t-tm, .t-ts).emph {
  font-weight: 650;
}

.aa :is(.t-bl, .t-bm, .t-bs).emph {
  font-weight: 560;
}

.aa :is(.t-ll, .t-lm, .t-ls).emph {
  font-weight: 700;
}

/* ---------- Text fields: BeerCSS outlined .field.border + a static label above ----------
   The design's rule, and the owner's: no floating labels anywhere (BeerCSS's
   .field.label is not used) — the label sits above the field, always visible,
   full size. Markup (the macro in view/storefront/component/forms.html):
     <div class="aa-fld"><label for="x">Label <span class="opt">(opsional)</span></label>
       <div class="field border [prefix]"><i>icon</i><input id="x"><output>Help</output></div></div>
   Ported from the design's theme.css ("Text fields"), the textarea's
   variant included (the contact form and the tickets write in one). */

/* The label above its field, 8 px apart. */
.aa .aa-fld {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}

/* .aa-lbl: the same label for a group without one input ("Pilih lisensi"). */
.aa :is(.aa-fld > label, .aa-lbl) {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: 14px;
  line-height: 20px;
  font-weight: 600;
  letter-spacing: 0.1px;
  color: var(--on-surface);
  white-space: normal;
}

/* "(opsional)" after the label of a field that may stay empty. */
.aa :is(.aa-fld > label, .aa-lbl) .opt {
  font-weight: 400;
  color: var(--on-surface-variant);
}

/* A field with an error: its label turns red with the border. */
.aa .aa-fld.invalid > label {
  color: var(--error);
}

.aa .aa-fld > .field {
  margin: 0;
}

.aa .field.border {
  border-radius: 8px;
}

.aa .field.border > :is(input, select, textarea) {
  color: var(--on-surface);
  caret-color: var(--primary);
}

/* The compact field (40 px: the catalogue's price and sort fields). */
.aa .field.border.small > :is(input, select) {
  font-size: 14px;
}

/* A textarea's lines 22 px apart with 12 px of room under them (the
   design's theme.css; BeerCSS leaves none, and its own 11.2 px on top — one
   more specific rule — stays: less than a pixel from the design). */
.aa .field.border > textarea {
  padding-block: 12px;
  line-height: 22px;
}

.aa .field.border > :is(input, textarea)::placeholder {
  color: var(--on-surface-variant);
  opacity: 0.75;
}

/* Hover darkens the border, but never over the focus or error colour. */
.aa .field.border:hover > :is(input, select, textarea):not(:focus, :disabled) {
  border-color: var(--on-surface);
}

.aa .field.border.invalid:hover > :is(input, select, textarea) {
  border-color: var(--error);
}

/* A prefix / suffix icon inside the field. */
.aa .field.border > i {
  color: var(--on-surface-variant);
}

.aa .field.border.invalid > i {
  color: var(--error);
}

/* ONE focus ring: BeerCSS turns the field's own border 2 px brand blue on
   focus, so the global focus outline (Base) must not draw a second ring
   around it — the double border seen on the sign-in pages. The browser smoke
   test checks every field: no outline, and a border that thickens. */
.aa .field > :is(input, select, textarea):focus-visible {
  outline: none;
}

/* Help text under the field; an error message replaces it, in red. */
.aa .field.border > output {
  padding: 6px 0 0;
  font-size: 12px;
  line-height: 16px;
  color: var(--on-surface-variant);
}

.aa .field.border > output.invalid {
  color: var(--error);
}

/* A field and its button side by side ("Kode voucher" + "Pakai"). */
.aa .aa-fld-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 8px;
  align-items: start;
}

/* ---------- Code boxes: a mailed 6-digit code ----------
   Every page that asks for one: signing in (page and dialog), "Ubah email",
   "Hapus akun", a paid page's "Simpan pembelian ke akun?" — so here, not in
   css/page/signin.css. One real input: a pasted or autofilled code arrives
   whole, screen readers hear one field. Without scripts it is a plain
   field; with scripts (html.js) it lies invisible over the design's six
   boxes, which app.js fills as the digits come ("the code boxes"). The
   digits in the codes' face, Roboto (decision 137): its figures are all
   one width, so the six boxes' digits sit alike. */
.aa .si-otp {
  position: relative;
}

.aa .si-otp > input {
  box-sizing: border-box;
  width: 100%;
  height: 56px;
  padding: 0 16px;
  border: 1px solid var(--outline);
  border-radius: 8px;
  background: var(--aa-raised);
  color: var(--on-surface);
  font-family: var(--font-code);
  font-size: 22px;
  letter-spacing: 0.3em;
}

.aa .si-otp > input:focus {
  border: 2px solid var(--primary);
  outline: none;
}

.aa .si-otp .si-boxes {
  display: none;
}

/* `:where(html.js)` adds no specificity: it sets none of the properties of
   the focus rule above, and a later rule ending in `input` (the sign-in's
   password field) must not sort below it (Biome's
   noDescendingSpecificity). */
:where(html.js) .aa .si-otp > input {
  position: absolute;
  inset: 0;
  z-index: 1;
  height: 100%;
  opacity: 0;
  /* 16 px keeps iPhones from zooming into the field. */
  font-size: 16px;
  caret-color: transparent;
  cursor: text;
}

html.js .aa .si-otp .si-boxes {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 10px;
}

html.js .aa .si-boxes > span {
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 64px;
  border: 1px solid var(--outline);
  border-radius: 8px;
  background: var(--aa-raised);
  color: var(--on-surface);
  font-family: var(--font-code);
  font-size: 26px;
  font-weight: 500;
}

html.js .aa .si-boxes > span.filled {
  background: var(--aa-inset);
}

html.js .aa .si-boxes > span.on {
  border: 2px solid var(--primary);
}

html.js .aa .aa-fld.invalid .si-boxes > span {
  border-color: var(--error);
}

/* A refusal under the boxes (the paid page's card; the sign-in's stands
   above the form), in the field's error words' size and red. */
.aa .si-otp-e {
  font-size: 12px;
  line-height: 16px;
  color: var(--error);
}

/* Phones: the six boxes a little smaller, closer together. */
@media (max-width: 600px) {
  html.js .aa .si-otp .si-boxes {
    gap: 8px;
  }

  html.js .aa .si-boxes > span {
    height: 56px;
    font-size: 22px;
  }
}

/* ---------- "Kabari saya": the newsletter in a box (component/notify.html; decision 106) ----------
   The home page's "Segera hadir" band and a coming-soon category's page. The
   e-mail field and its button share a row (.aa-fld-row); a refusal stands
   above it; once sent, one line replaces the form. */
.aa .aa-notify {
  min-width: 0;
}

.aa .aa-notify-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 0;
}

.aa .aa-notify-alert,
.aa .aa-notify-sent {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin: 0;
  font-size: 14px;
  line-height: 21px;
}

.aa .aa-notify-alert {
  padding: 10px 14px;
  border-radius: 14px;
  background: var(--error-container);
  color: var(--on-error-container);
}

.aa .aa-notify-sent {
  padding: 14px 16px;
  border-radius: 16px;
  background: var(--aa-raised);
  color: var(--on-surface);
}

/* The sent line's envelope in the brand's colour (a class of its own: a
   rule ending in a bare `i` would sort before the fields' icons). */
.aa .aa-notify-icon {
  color: var(--primary);
}

/* ---------- Buttons: BeerCSS defaults + weight for Google Sans Flex ---------- */

.aa :is(button, .button) {
  font-weight: 560;
  letter-spacing: 0.1px;
}

.aa :is(button, .button).extra {
  font-size: 16px;
}

/* Outlined button on a dark band (bespoke section). */
.aa :is(button, .button).on-dark.border {
  border-color: rgb(255 255 255 / 0.55);
  color: #ffffff;
}

/* Full-width button (phone CTAs). */
.aa :is(button, .button).block {
  width: 100%;
  box-sizing: border-box;
}

/* Connected button groups (home tabs): the selected one is the brand container. */
.aa nav.group.connected > :is(button, .button) {
  font-weight: 600;
}

.aa nav.group.connected > :is(button, .button).active {
  background-color: var(--primary-container);
  color: var(--on-primary-container);
}

.aa nav.group.connected > :is(button, .button).active > i {
  font-variation-settings: "FILL" 1;
}

/* ---------- Chips ---------- */

.aa .chip {
  font-weight: 500;
  letter-spacing: 0.1px;
  color: var(--on-surface-variant);
}

/* A selected filter chip (category, price): the secondary container. */
.aa .chip.is-on {
  background-color: var(--secondary-container);
  color: var(--on-secondary-container);
  border-color: transparent;
}

/* ---------- Header (white app bar + search + main nav) ---------- */

/* Not sticky on desktop (as designed); above the page so the search menu
   can overlap the hero. */
.aa .aa-hdr {
  display: block;
  min-block-size: 0;
  padding: 0;
  background: var(--aa-header);
  color: var(--on-surface);
  border-block-end: 1px solid var(--outline-variant);
  position: relative;
  z-index: 30;
  border-radius: 0;
}

.aa .aa-hdr-top {
  display: flex;
  align-items: center;
  gap: 24px;
  height: 80px;
  padding: 0 64px;
}

/* The logo link: its own rounded focus ring; the image keeps its ratio
   (the shared-A lockup, 1000 : 356). Never under 120 px wide on screen — the
   logo's own rule (its README, 2026-10-01); smaller places use the favicon.
   Every wordmark image has square corners (here, the drawer's, the bar's and
   the footers'): BeerCSS's `* { border-radius: inherit }` would hand it its
   container's — this link's 8 px ring, the drawer's 28 px edge — and an
   image is clipped to its own corners, which cut the i's dot at the logo's
   top-right corner and, in the drawer, the tops of "plikasi" and the
   underline's point (decision 149). */
.aa .aa-logo {
  display: inline-flex;
  flex: none;
  border-radius: 8px;
}

.aa .aa-logo img {
  width: 130px;
  height: 46px;
  border-radius: 0;
}

/* Search bar — one outlined pill: category menu on the left, divider, icon,
   input. No submit button: Enter searches (the form's implicit submission). */
.aa .aa-search {
  position: relative;
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  height: 48px;
  padding: 0 16px 0 0;
  border-radius: 24px;
  border: 1px solid var(--outline-variant);
  background: var(--aa-raised);
  color: var(--on-surface);
  transition:
    border-color var(--speed2),
    box-shadow var(--speed2);
}

.aa .aa-search:hover {
  border-color: var(--outline);
}

/* The whole pill shows focus while the text field has it. */
.aa :is(.aa-search, .m-search):has(> input:focus) {
  border-color: var(--primary);
  box-shadow: 0 0 0 1px var(--primary);
}

.aa .aa-search > i {
  flex: none;
  margin: 0 2px 0 14px;
  color: var(--on-surface-variant);
}

/* `all: unset` drops BeerCSS's field styling: the pill is the field. */
.aa .aa-search input {
  all: unset;
  box-sizing: border-box;
  flex: 1 1 auto;
  min-width: 0;
  height: 100%;
  padding: 0 8px;
  font-family: var(--font);
  font-size: 15px;
  letter-spacing: 0.1px;
  color: var(--on-surface);
  text-overflow: ellipsis;
}

.aa :is(.aa-search, .m-search) input::placeholder {
  color: var(--on-surface-variant);
  opacity: 1;
}

/* The pill has its own clear affordance (none); the ring is on the pill. */
.aa :is(.aa-search, .m-search) input::-webkit-search-cancel-button {
  display: none;
}

.aa :is(.aa-search, .m-search) input:focus-visible {
  outline: none;
}

/* The category menu button inside the pill. */
.aa .aa-search-cat {
  all: unset;
  box-sizing: border-box;
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 100%;
  padding: 0 14px 0 20px;
  border-radius: 24px 0 0 24px;
  font-family: var(--font);
  font-size: 14px;
  line-height: 20px;
  font-weight: 600;
  letter-spacing: 0.1px;
  color: var(--on-surface);
  white-space: nowrap;
  cursor: pointer;
}

/* BeerCSS draws a ripple layer on every button; not on this one. */
.aa :is(.aa-search-cat, .aa-search-menu button)::after {
  display: none;
}

.aa .aa-search-cat:hover {
  color: var(--primary);
}

.aa .aa-search-cat:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: -4px;
}

.aa .aa-search-cat > i {
  --_size: 20px;
  font-size: 20px;
  color: var(--on-surface-variant);
  transition: transform var(--speed2);
}

.aa .aa-search-cat[aria-expanded="true"] > i {
  transform: rotate(180deg);
}

.aa .aa-search-sep {
  flex: none;
  width: 1px;
  height: 24px;
  background: var(--outline-variant);
  border-radius: 0;
}

/* The M3 menu under the category button (a listbox; app.js opens it). */
.aa .aa-search-menu {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 45;
  display: flex;
  flex-direction: column;
  min-width: 272px;
  padding: 8px 0;
  border-radius: 16px;
  background: var(--surface-container);
  box-shadow: var(--elevate2);
}

/* `hidden` must win over the display: flex above. */
.aa .aa-search-menu[hidden] {
  display: none;
}

.aa .aa-search-menu button {
  all: unset;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  gap: 12px;
  height: 44px;
  padding: 0 16px;
  font-family: var(--font);
  font-size: 14px;
  line-height: 20px;
  color: var(--on-surface);
  cursor: pointer;
  border-radius: 0;
}

.aa .aa-search-menu button:is(:hover, :focus-visible) {
  background: var(--active);
}

.aa .aa-search-menu button:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: -2px;
}

.aa .aa-search-menu button.is-on {
  background: var(--secondary-container);
  color: var(--on-secondary-container);
  font-weight: 600;
}

.aa .aa-search-menu button > i {
  --_size: 20px;
  font-size: 20px;
  color: var(--on-surface-variant);
}

/* The check mark follows the selection (every option carries one). */
.aa .aa-search-menu button > i.check {
  margin-left: auto;
  color: inherit;
}

.aa .aa-search-menu button:not(.is-on) > i.check {
  display: none;
}

/* Right side of the top row: All products, cart, sign-in / account. */
.aa .aa-hdr-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: none;
}

.aa .aa-hdr-actions .badge {
  font-weight: 600;
  font-size: 11px;
  min-block-size: 16px;
  min-inline-size: 16px;
}

/* The signed-in customer's initials. */
.aa .aa-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--tertiary-container);
  color: var(--on-tertiary-container);
  font-weight: 650;
  font-size: 15px;
  letter-spacing: 0;
  flex: none;
}

/* The account menu (decision 128): the account button is a <details>'
   summary; its panel hangs from the button's right edge like the search
   pill's menu, over the page (the <details> carries the z-index: Chrome
   paints later boxes over an absolute child otherwise). */
.aa .aa-acctmenu {
  position: relative;
  z-index: 45;
}

.aa .aa-acctmenu > summary {
  list-style: none;
}

.aa .aa-acctmenu > summary::-webkit-details-marker {
  display: none;
}

/* BeerCSS draws a line under a summary in its lists: not under a button. */
.aa .aa-acctmenu > summary::before {
  content: none;
}

/* :where(): as specific as a rule for any icon (Biome's
   noDescendingSpecificity, whose count must not grow); still above BeerCSS's.
   The open menu's rule comes later, so it wins. */
.aa :where(.aa-acctmenu > summary > i) {
  transition: transform var(--speed2);
}

.aa :where(.aa-acctmenu[open] > summary > i) {
  transform: rotate(180deg);
}

.aa .aa-acct-panel {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  display: flex;
  flex-direction: column;
  width: 288px;
  padding: 8px 0;
  border-radius: 16px;
  background: var(--surface-container);
  box-shadow: var(--elevate2);
}

/* Who is signed in: the avatar and the name (cut with "…"). Never the
   address: no shop page prints a customer's address (a screen shown or
   shared keeps it private). */
.aa .aa-acct-who {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 16px 12px;
}

.aa .aa-acct-who .nm {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-weight: 600;
  font-size: 14px;
  line-height: 20px;
  color: var(--on-surface);
}

.aa .aa-acct-sep {
  margin: 8px 0;
  border-top: 1px solid var(--outline-variant);
}

/* A link (or "Keluar", a form's button — the form is `no-margin`: BeerCSS
   puts 1 rem above a form that follows another element) per row: 44 px, a
   tap target. */
.aa .aa-acct-link {
  all: unset;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  height: 44px;
  padding: 0 16px;
  font-family: var(--font);
  font-size: 14px;
  line-height: 20px;
  color: var(--on-surface);
  cursor: pointer;
  border-radius: 0;
}

.aa .aa-acct-link:is(:hover, :focus-visible) {
  background: var(--active);
}

.aa .aa-acct-link:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: -2px;
}

.aa .aa-acct-link.is-on {
  background: var(--secondary-container);
  color: var(--on-secondary-container);
  font-weight: 600;
}

.aa :where(.aa-acct-link > i) {
  --_size: 20px;
  font-size: 20px;
  color: var(--on-surface-variant);
}

/* Second row: the main navigation and the language / theme controls. */
.aa .aa-hdr-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 56px;
  padding: 0 56px;
}

/* The categories are the admin's to arrange (decision 106): when more than
   fit, the row scrolls sideways (no scrollbar, as on tablets) instead of
   pushing the language and theme controls out; 4 px above and below keep
   the focus rings visible. */
.aa .aa-mainnav {
  display: flex;
  align-items: center;
  gap: 2px;
  min-width: 0;
  overflow-x: auto;
  padding-block: 4px;
  scrollbar-width: none;
}

.aa .aa-navlink {
  height: 40px;
  padding: 0 16px;
  gap: 6px;
  background: transparent;
  color: var(--on-surface-variant);
  font-weight: 560;
  border-radius: 20px;
}

.aa .aa-navlink:hover {
  color: var(--on-surface);
}

.aa .aa-navlink.is-current {
  background: var(--secondary-container);
  color: var(--on-secondary-container);
}

.aa .aa-prefs {
  display: flex;
  align-items: center;
  gap: 12px;
}

/* The language toggle and the theme button are shared with the admin panel's
   top bar: components.css ("Language toggle and theme button"). */

/* ---------- Category colour helpers ---------- */

/* `.cat-<key>` picks a colour set; components read --cc / --cc-c / --cc-on. */
.aa .cat-excel {
  --cc: var(--c-excel);
  --cc-c: var(--c-excel-c);
  --cc-on: var(--c-excel-on);
}

.aa .cat-sheets {
  --cc: var(--c-sheets);
  --cc-c: var(--c-sheets-c);
  --cc-on: var(--c-sheets-on);
}

.aa .cat-webapp {
  --cc: var(--c-webapp);
  --cc-c: var(--c-webapp-c);
  --cc-on: var(--c-webapp-on);
}

.aa .cat-landing {
  --cc: var(--c-landing);
  --cc-c: var(--c-landing-c);
  --cc-on: var(--c-landing-on);
}

.aa .cat-graphics {
  --cc: var(--c-graphics);
  --cc-c: var(--c-graphics-c);
  --cc-on: var(--c-graphics-on);
}

.aa .cat-video {
  --cc: var(--c-video);
  --cc-c: var(--c-video-c);
  --cc-on: var(--c-video-on);
}

.aa .cat-audio {
  --cc: var(--c-audio);
  --cc-c: var(--c-audio-c);
  --cc-on: var(--c-audio-on);
}

.aa .cat-bespoke {
  --cc: var(--c-bespoke);
  --cc-c: var(--c-bespoke-c);
  --cc-on: var(--c-bespoke-on);
}

.aa .cat-invite {
  --cc: var(--c-invite);
  --cc-c: var(--c-invite-c);
  --cc-on: var(--c-invite-on);
}

/* A category added later (no colour set of its own) borrows the brand's. */
.aa .cat-other {
  --cc: var(--primary);
  --cc-c: var(--primary-container);
  --cc-on: var(--on-primary-container);
}

/* The category icon on an expressive shape. */
.aa .shape.cc {
  background-color: var(--cc-c);
  color: var(--cc-on);
}

/* ---------- Product card ---------- */

.aa .aa-pcard {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  background: var(--aa-raised);
  color: var(--on-surface);
  border-radius: 24px;
  box-shadow: var(--elevate1);
  transition:
    box-shadow var(--speed3),
    transform var(--speed3);
}

.aa .aa-pcard:hover {
  box-shadow: var(--elevate2);
}

.aa .aa-pmedia {
  position: relative;
  display: block;
  margin: 8px 8px 0;
  border-radius: 16px;
  overflow: hidden;
  line-height: 0;
  background: var(--surface-container);
}

/* The picture covers the design's image box: BeerCSS pads an <article> by
   16 px, so the box is 262 × 184 px on the 1440 px board (199 × 144 on
   tablets, 129 × 101 on phones — see below). A 16:10 picture is scaled to the
   box's height and anchored left, so its right edge is cut off — exactly how
   the design renders its drawn thumbnails. */
.aa .aa-pmedia img {
  width: 100%;
  height: auto;
  aspect-ratio: 262 / 184;
  object-fit: cover;
  object-position: left center;
}

/* The one label on the image: sale, new or best seller. */
.aa .aa-ptag {
  position: absolute;
  top: 18px;
  left: 18px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 24px;
  padding: 0 10px;
  border-radius: 12px;
  font-size: 12px;
  line-height: 16px;
  font-weight: 700;
  letter-spacing: 0.3px;
  z-index: 2;
}

.aa .aa-ptag.sale {
  background: var(--aa-sale);
  color: var(--aa-on-sale);
}

.aa .aa-ptag.new {
  background: var(--tertiary-container);
  color: var(--on-tertiary-container);
}

.aa .aa-ptag.best {
  background: var(--aa-warn-container);
  color: var(--aa-on-warn-container);
}

/* A special discount's label (decision 103, the owner's "eye-catching"): the
   red-to-orange chip with a lightning bolt and a slow glow around it — the
   glow pulses outside the chip, so the words keep their contrast. */
.aa .aa-ptag.special {
  background: linear-gradient(135deg, var(--aa-special-from), var(--aa-special-to));
  color: var(--aa-on-special);
  animation: aa-special-glow 2.4s ease-in-out infinite;
}

/* The chip's bolt, by a class of its own: Biome orders every rule ending in
   an <i> by its weight, file-wide. */
.aa .aa-bolt {
  --_size: 14px;
  font-size: 14px;
}

@keyframes aa-special-glow {
  0%,
  100% {
    box-shadow: 0 2px 8px rgb(191 54 12 / 0.3);
  }

  50% {
    box-shadow:
      0 0 0 4px rgb(230 74 25 / 0.22),
      0 2px 14px rgb(191 54 12 / 0.45);
  }
}

/* The card (and the catalogue's row) of a special discount stands out with
   a ring in the chip's orange — a shadow, so the card keeps the design's
   measurements — and its price takes the same colour. */
.aa :is(.aa-pcard, .pr-row).is-special {
  box-shadow:
    0 0 0 2px var(--aa-special-to),
    0 10px 28px rgb(191 54 12 / 0.16);
}

.aa .aa-price.is-special {
  color: var(--aa-special-to);
}

@media (prefers-reduced-motion: reduce) {
  .aa .aa-ptag.special {
    animation: none;
  }
}

/* Save to favourites, on the image. */
.aa .aa-pfav {
  position: absolute;
  top: 16px;
  right: 16px;
  z-index: 2;
  background: var(--aa-raised);
  color: var(--on-surface-variant);
  box-shadow: var(--elevate1);
}

.aa .aa-pfav.is-on {
  color: var(--error);
}

.aa .aa-pfav.is-on > i {
  font-variation-settings: "FILL" 1;
}

.aa .aa-pbody {
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex: 1 1 auto;
  padding: 12px 16px 16px;
}

/* Category line in the category's colour. */
.aa .aa-pcat {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  line-height: 16px;
  font-weight: 600;
  letter-spacing: 0.2px;
  color: var(--cc);
}

.aa .aa-pcat > i {
  font-size: 16px;
  --_size: 16px;
}

/* Two lines at most, and always two lines tall, so the cards line up.
   border-radius 0: BeerCSS rounds every element, which clips the first letters. */
.aa .aa-ptitle {
  display: -webkit-box;
  justify-content: flex-start;
  align-items: flex-start;
  text-align: start;
  border-radius: 0;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: 44px;
  font-size: 16px;
  line-height: 22px;
  font-weight: 620;
  letter-spacing: 0;
  color: var(--on-surface);
}

.aa .aa-pmeta {
  display: flex;
  align-items: center;
  gap: 4px;
  flex-wrap: wrap;
  font-size: 12px;
  line-height: 16px;
  letter-spacing: 0.1px;
  color: var(--on-surface-variant);
}

.aa .aa-pmeta b {
  color: var(--on-surface);
  font-weight: 650;
}

.aa .aa-pmeta > i {
  --_size: 16px;
  font-size: 16px;
}

/* Rating stars are filled icons. */
.aa .aa-star {
  color: var(--aa-star);
  font-variation-settings: "FILL" 1;
}

.aa i.aa-star {
  --_size: 16px;
  font-size: 16px;
}

/* The stars a rating does not reach (the rating filter's "4 ke atas"). */
.aa .aa-star-off {
  color: var(--outline-variant);
  font-variation-settings: "FILL" 1;
}

/* Price block at the bottom of the text (pushes to the bottom of the card). */
.aa .aa-pfoot {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 8px;
  margin-top: auto;
  padding-top: 10px;
}

.aa .aa-pprice {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.aa .aa-prow {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
}

.aa .aa-price {
  font-size: 20px;
  line-height: 26px;
  font-weight: 720;
  letter-spacing: -0.2px;
  color: var(--on-surface);
  font-variant-numeric: tabular-nums;
}

.aa .aa-was {
  font-size: 12px;
  line-height: 16px;
  color: var(--on-surface-variant);
  text-decoration: line-through;
}

.aa .aa-from {
  font-size: 12px;
  line-height: 16px;
  font-weight: 500;
  letter-spacing: 0.1px;
  color: var(--on-surface-variant);
}

.aa .aa-sub {
  font-size: 12px;
  line-height: 16px;
  color: var(--on-surface-variant);
}

/* Card actions: one prominent Beli (filled, full width, opens Fast Checkout)
   and, on its own row under it, the second choices side by side — the cart
   button (decision 147) and a small tonal "Lihat detail" pill — easy to
   find, but clearly second. */
.aa .aa-pbtns {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
  margin-top: 14px;
}

.aa .aa-pbtns > .pb-buy {
  --_size: 44px;
  min-width: 0;
  padding: 0 16px;
  gap: 8px;
  border-radius: 22px;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.1px;
  white-space: nowrap;
}

.aa .aa-pbtns > .pb-buy > i {
  --_size: 20px;
  font-size: 20px;
  font-variation-settings: "FILL" 1;
}

/* The row of the second choices, centred under Beli. */
.aa .aa-pbtns > .pb-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-width: 0;
}

.aa .pb-row > .pb-dtl {
  --_size: 32px;
  min-width: 0;
  max-width: 100%;
  margin: 0;
  padding: 0 14px 0 10px;
  gap: 6px;
  border-radius: 16px;
  background-color: var(--secondary-container);
  color: var(--on-secondary-container);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.1px;
  white-space: nowrap;
}

/* The cart button (decision 147): an icon, as the product page's floating
   bar's — round, in the detail pill's tonal colour and height, its sibling.
   Once the product is in the cart (app.js) it is the link to the cart, its
   icon "shopping_cart_checkout". */
.aa .pb-row > .pb-cart {
  --_size: 32px;
  flex: none;
  margin: 0;
  background-color: var(--secondary-container);
  color: var(--on-secondary-container);
}

.aa .pb-row > :is(.pb-dtl, .pb-cart) > i {
  --_size: 18px;
  font-size: 18px;
}

/* ---------- Section heads ---------- */

/* Title + subtitle on the left, links / tabs on the right, bottom-aligned. */
.aa .aa-sechead {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 24px;
}

.aa .aa-sechead > div:first-child {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.aa .aa-sechead > div + div {
  display: flex;
  align-items: center;
  gap: 16px;
}

/* ---------- Status pills, separator, number and code text ---------- */

/* A short state on a tinted pill (product page: "Pilihan", "Publik",
   "Terbaru"; later orders, tickets and hosting). */
.aa .aa-status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 28px;
  padding: 0 12px;
  border-radius: 14px;
  font-size: 12px;
  font-weight: 650;
  letter-spacing: 0.3px;
  white-space: nowrap;
}

/* :where(): as specific as a rule for any icon (Biome's
   noDescendingSpecificity, whose count must not grow); still above BeerCSS's. */
.aa .aa-status > :where(i) {
  --_size: 16px;
  font-size: 16px;
}

.aa .aa-status.ok {
  background: var(--aa-success-container);
  color: var(--aa-on-success-container);
}

.aa .aa-status.wait {
  background: var(--aa-warn-container);
  color: var(--aa-on-warn-container);
}

.aa .aa-status.info {
  background: var(--primary-container);
  color: var(--on-primary-container);
}

.aa .aa-status.bad {
  background: var(--error-container);
  color: var(--on-error-container);
}

.aa .aa-status.neutral {
  background: var(--surface-container-highest);
  color: var(--on-surface-variant);
}

/* A hairline between two parts of a card (an <hr>: no margins of its own). */
.aa .aa-sep {
  height: 1px;
  margin: 0;
  background: var(--outline-variant);
  border: 0;
}

/* Figures that line up in columns (prices, counters). */
.aa .tnum {
  font-variant-numeric: tabular-nums;
}

/* Codes: order and ticket numbers, license and purchase codes, file
   passwords, versions and file names — what people read out or type in —
   in Roboto (the owner, 2026-10-15, decision 137; Roboto Mono before),
   self-hosted (fonts.css). Its figures are all one width, so a code keeps
   its columns; set apart from the words around it by its face alone. */
.aa .code-text {
  font-family: var(--font-code);
  letter-spacing: 0;
}

/* ---------- Testimonials: buyers' chat screenshots (product page) ---------- */

/* The label above the band's heading. */
.aa .tm-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 32px;
  padding: 0 14px 0 10px;
  border-radius: 16px;
  background: var(--primary-container);
  color: var(--on-primary-container);
  font-size: 13px;
  line-height: 16px;
  font-weight: 700;
  letter-spacing: 0.3px;
}

.aa .tm-eyebrow :where(i) {
  --_size: 18px;
  font-size: 18px;
  font-variation-settings: "FILL" 1;
}

/* The product's name inside the heading. */
.aa .tm-hl {
  color: var(--primary);
}

/* Stars, score and "Lihat semua ulasan" on one white pill. */
.aa .tm-rating {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px 10px;
  min-height: 40px;
  padding: 4px 6px 4px 16px;
  border-radius: 20px;
  background: var(--aa-raised);
  box-shadow: var(--elevate1);
  font-size: 14px;
  line-height: 20px;
}

.aa .tm-rating b {
  font-size: 16px;
  font-weight: 760;
}

/* One card: the chat app's bar and the screenshot in a frame, the buyer's
   name, business and "Pembeli terverifikasi" under it. The screenshot is the
   buyer's own picture — it keeps its colours in dark mode. */
.aa .tm-shot {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-width: 0;
  margin: 0;
}

.aa .tm-shot .frame {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  border-radius: 24px;
  overflow: hidden;
  background: var(--surface-container);
  box-shadow:
    0 0 0 1px var(--outline-variant),
    var(--elevate2);
}

.aa .tm-shot .bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 6px 10px 12px;
  background: var(--aa-raised);
  box-shadow: 0 1px 0 var(--outline-variant);
  border-radius: 0;
}

.aa .tm-shot .bar .who {
  display: flex;
  flex-direction: column;
  min-width: 0;
  flex: 1 1 auto;
}

/* border-radius 0: with overflow hidden, BeerCSS's rounding would clip the
   first letter. */
.aa .tm-shot .bar .nm {
  font-size: 14px;
  line-height: 18px;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  border-radius: 0;
}

.aa .tm-shot .bar .src {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  line-height: 14px;
  font-weight: 600;
  color: var(--on-surface-variant);
}

.aa .tm-shot :where(.bar .src i) {
  --_size: 14px;
  font-size: 14px;
}

.aa .tm-shot.src-wa :where(.bar .src i) {
  color: var(--aa-success);
}

.aa .tm-shot.src-ig :where(.bar .src i) {
  color: var(--tertiary);
}

.aa .tm-shot .tm-zoom {
  flex: none;
  color: var(--on-surface-variant);
}

.aa .tm-shot .shot {
  width: 100%;
  height: auto;
}

.aa .tm-shot figcaption {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 0 6px;
}

.aa .tm-shot figcaption :where(.nm) {
  font-size: 15px;
  line-height: 20px;
  font-weight: 700;
}

.aa .tm-shot figcaption .bz {
  font-size: 13px;
  line-height: 18px;
  color: var(--on-surface-variant);
}

.aa .tm-shot figcaption .vf {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: 4px;
  font-size: 12px;
  line-height: 16px;
  font-weight: 650;
  color: var(--aa-success);
}

.aa .tm-shot figcaption .vf :where(i) {
  --_size: 16px;
  font-size: 16px;
  font-variation-settings: "FILL" 1;
}

/* The buyer's initials on a colour of the design's four. */
.aa .tm-av {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  font-size: 12px;
  font-weight: 750;
  letter-spacing: 0.3px;
}

.aa .tm-av.tone-a {
  background-color: var(--tertiary-container);
  color: var(--on-tertiary-container);
}

.aa .tm-av.tone-b {
  background-color: var(--secondary-container);
  color: var(--on-secondary-container);
}

.aa .tm-av.tone-c {
  background-color: var(--aa-success-container);
  color: var(--aa-on-success-container);
}

.aa .tm-av.tone-d {
  background-color: var(--aa-warn-container);
  color: var(--aa-on-warn-container);
}

/* ---------- Sharing ---------- */

/* "Bagikan" needs app.js (the phone's share sheet, or the link copied): a
   button that cannot work is not shown without it. */
html:not(.js) .aa [data-share] {
  display: none;
}

/* ---------- Footer (brand grey #3E3E3E) ---------- */

.aa .aa-footer {
  display: block;
  min-block-size: 0;
  padding: 0;
  border-radius: 0;
  background: var(--aa-footer);
  color: var(--aa-on-footer);
}

/* Cara Order · Blog · Kontak: the first thing in the footer, as three large link cards. */
.aa .aa-foot-quick {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  /* A <nav> here: BeerCSS centres a nav's items; the cards share one height. */
  align-items: stretch;
  gap: 16px;
  padding: 40px 0 32px;
  border-bottom: 1px solid var(--aa-footer-line);
  border-radius: 0;
}

.aa .aa-quick {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
  gap: 8px;
  padding: 16px 20px 18px 16px;
  border-radius: 24px;
  background: rgb(255 255 255 / 0.07);
  box-shadow: inset 0 0 0 1px var(--aa-footer-line);
  color: var(--aa-on-footer);
  text-align: start;
  white-space: normal;
  transition: background-color var(--speed2);
}

.aa .aa-quick:hover {
  background: rgb(255 255 255 / 0.12);
}

.aa .aa-quick .hd {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  border-radius: 0;
}

.aa .aa-quick .ic {
  flex: none;
  width: 36px;
  height: 36px;
  background-color: var(--inverse-primary);
  color: #001c39;
}

.aa .aa-quick .ic i {
  --_size: 20px;
  font-size: 20px;
}

.aa.dark .aa-quick .ic {
  background-color: var(--primary);
  color: var(--on-primary);
}

.aa .aa-quick .h {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 18px;
  line-height: 24px;
  font-weight: 680;
  letter-spacing: -0.1px;
}

.aa .aa-quick .d {
  font-size: 14px;
  line-height: 20px;
  color: var(--aa-footer-muted);
}

.aa .aa-quick .go {
  flex: none;
  color: var(--aa-footer-link);
  transition: transform var(--speed2);
}

.aa .aa-quick:hover .go {
  transform: translateX(4px);
}

.aa .aa-quick.is-current {
  background: rgb(255 255 255 / 0.12);
  box-shadow: inset 0 0 0 2px var(--aa-footer-link);
}

/* Brand column + four link columns. */
.aa .aa-foot-main {
  display: grid;
  grid-template-columns: 1.35fr repeat(4, minmax(0, 1fr));
  gap: 40px;
  padding: 40px 0 48px;
}

.aa .aa-foot-brand {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 20px;
}

.aa .aa-foot-brand > a {
  border-radius: 8px;
}

/* The footer's wordmark: square corners, not its link's ring (see
   .aa-logo img). */
.aa .aa-foot-brand img {
  width: 157px;
  height: 56px;
  border-radius: 0;
}

.aa .aa-foot-about {
  color: var(--aa-footer-muted);
  max-width: 300px;
}

/* Who runs the shop (decision 110), in both footers: a small label, the
   company's name — a link to its own site, its new-tab mark beside it — and
   that site's line about it, under the shop's description. */
.aa .aa-foot-company {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
}

/* Desktop and tablet: as wide as the description above it (phones: the
   footer's whole width, as their description). */
.aa .aa-foot-brand > .aa-foot-company {
  max-width: 300px;
}

.aa .aa-colabel {
  font-size: 12px;
  line-height: 16px;
  font-weight: 600;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--aa-footer-muted);
}

.aa .aa-coname {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 15px;
  line-height: 22px;
  font-weight: 700;
  color: var(--aa-on-footer);
}

.aa .aa-coname:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* The new-tab mark: a class of its own, not `… i` (Biome's
   noDescendingSpecificity compares every rule ending in `i`, file-wide). */
.aa .aa-coext {
  --_size: 16px;
  font-size: 16px;
  color: var(--aa-footer-link);
}

.aa .aa-coabout {
  font-size: 13px;
  line-height: 18px;
  color: var(--aa-footer-muted);
}

.aa .aa-foot-col {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.aa .aa-foot-h {
  font-size: 14px;
  line-height: 20px;
  font-weight: 700;
  letter-spacing: 0.1px;
  color: var(--aa-on-footer);
}

.aa .aa-foot-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.aa .aa-foot-list a {
  display: inline;
  color: var(--aa-footer-muted);
  font-size: 14px;
  line-height: 20px;
}

.aa .aa-foot-list a:hover {
  color: var(--aa-on-footer);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Support contacts (e-mail and WhatsApp are links; they look like the design's text). */
.aa .aa-foot-contact {
  display: flex;
  flex-direction: column;
  gap: 10px;
  color: var(--aa-footer-muted);
  font-size: 14px;
  line-height: 20px;
}

.aa .aa-foot-contact div {
  display: flex;
  align-items: center;
  gap: 10px;
}

.aa .aa-foot-contact a {
  color: inherit;
}

.aa .aa-foot-contact a:hover {
  color: var(--aa-on-footer);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.aa .aa-foot-contact i {
  --_size: 20px;
  font-size: 20px;
  color: var(--aa-footer-link);
}

/* Payment methods (by kind — gateway names never appear in our UI). */
.aa .aa-foot-pay {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 24px 0;
  border-top: 1px solid var(--aa-footer-line);
  color: var(--aa-footer-muted);
  font-size: 13px;
}

.aa .aa-foot-paytitle {
  color: var(--aa-on-footer);
  margin-right: 4px;
}

.aa .aa-foot-paynote {
  margin-left: auto;
}

.aa .aa-paychip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 32px;
  padding: 0 12px;
  border-radius: 8px;
  border: 1px solid var(--aa-footer-line);
  color: var(--aa-on-footer);
  font-size: 13px;
  font-weight: 600;
  background: rgb(255 255 255 / 0.04);
}

.aa .aa-paychip i {
  --_size: 18px;
  font-size: 18px;
  color: var(--aa-footer-link);
}

.aa .aa-foot-bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 20px 0 28px;
  border-top: 1px solid var(--aa-footer-line);
  color: var(--aa-footer-muted);
  font-size: 13px;
}

.aa .aa-foot-bottom nav {
  display: flex;
  gap: 20px;
}

.aa .aa-foot-bottom a {
  display: inline;
  color: var(--aa-footer-muted);
}

.aa .aa-foot-bottom a:hover {
  color: var(--aa-on-footer);
}

/* ---------- Expressive shapes ---------- */

/* BeerCSS's `.shape.<name>` masks (its sibling SVG files); an icon sits on top. */
.aa .shape {
  flex: none;
}

.aa .shape > i {
  position: relative;
  z-index: 1;
}

/* ---------- Navigation drawer (tablet and phone menu) ---------- */

/* A native <dialog> opened with showModal() (app.js): focus is trapped, Esc
   closes it and the page behind is inert — the design's drawer, with the
   accessibility a modal needs. Full height here (the design board is cut). */
.aa dialog.mm-drawer {
  position: fixed;
  inset: 0 auto 0 0;
  z-index: 90;
  width: min(316px, 100vw - 56px);
  min-inline-size: 0;
  height: 100dvh;
  max-height: none;
  max-width: none;
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: flex-start;
  gap: 2px;
  padding: 12px 12px 16px;
  border: 0;
  border-radius: 0 28px 28px 0;
  background: var(--aa-inset);
  color: var(--on-surface);
  box-shadow: var(--elevate3);
  overflow-x: hidden;
  overflow-y: auto;
  transform: translateX(-100%);
}

.aa dialog.mm-drawer[open] {
  transform: none;
}

/* The scrim behind the drawer (BeerCSS keeps backdrops invisible by default).
   Literal colours: older browsers do not pass custom properties to ::backdrop. */
.aa dialog.mm-drawer::backdrop {
  background: rgb(0 0 0 / 0.32);
}

.aa.dark dialog.mm-drawer::backdrop {
  background: rgb(0 0 0 / 0.5);
}

.aa dialog.mm-drawer[open]::backdrop {
  opacity: 1;
  visibility: visible;
}

.aa .mm-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 4px 4px 12px 12px;
}

/* The drawer's wordmark: square corners, not the drawer's rounded edge
   (see .aa-logo img). */
.aa .mm-head img {
  width: 120px;
  height: 43px;
  border-radius: 0;
}

/* The drawer's links (a <nav> for screen readers; BeerCSS would centre and
   space a nav's items, the design stacks them edge to edge). */
.aa .mm-links {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 2px;
}

.aa .mm-link {
  display: flex;
  flex: none;
  align-items: center;
  justify-content: flex-start;
  gap: 12px;
  height: 52px;
  padding: 0 16px;
  border-radius: 26px;
  color: var(--on-surface-variant);
  font-size: 15px;
  font-weight: 600;
  text-align: start;
}

.aa .mm-link.active {
  background: var(--secondary-container);
  color: var(--on-secondary-container);
}

.aa .mm-link.active i {
  font-variation-settings: "FILL" 1;
}

.aa .mm-morehead {
  padding: 14px 16px 6px;
  font-size: 12px;
  line-height: 16px;
  font-weight: 700;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--on-surface-variant);
}

.aa .mm-morerow {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 6px;
  padding: 0 4px;
}

.aa .mm-more {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-height: 64px;
  padding: 8px 4px;
  border-radius: 18px;
  background: var(--surface-container-high);
  color: var(--on-surface);
  font-size: 12px;
  line-height: 16px;
  font-weight: 650;
  text-align: center;
  white-space: normal;
}

.aa .mm-more i {
  --_size: 22px;
  font-size: 22px;
  color: var(--primary);
}

/* Language and theme at the bottom of the drawer. */
.aa .mm-prefs {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: auto;
  padding: 16px 12px 0;
  border-top: 1px solid var(--outline-variant);
  border-radius: 0;
}

.aa .mm-pref {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 44px;
  font-size: 14px;
  font-weight: 600;
}

/* ---------- Phone chrome: top app bar, search, bottom navigation, footer ---------- */

/* M3 small top app bar; stays on screen while scrolling. */
.aa .m-top {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 2px;
  height: 64px;
  min-block-size: 0;
  padding: 0 4px;
  background: var(--aa-header);
  color: var(--on-surface);
  border-radius: 0;
}

.aa .m-top .logo {
  display: inline-flex;
  margin-left: 4px;
  border-radius: 6px;
}

/* The phone bar's wordmark: square corners, not its link's ring (see
   .aa-logo img). */
.aa .m-top .logo img {
  width: 120px;
  height: 43px;
  border-radius: 0;
}

.aa .m-top-space {
  flex: 1 1 auto;
}

/* A sub-page's title beside its back arrow (the catalogue, a product). */
.aa .m-top .ttl {
  flex: 1 1 auto;
  min-width: 0;
  padding-left: 4px;
  font-size: 20px;
  line-height: 28px;
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  border-radius: 0;
}

.aa .m-top .badge {
  font-weight: 650;
}

.aa .m-top .m-signin {
  margin: 0 8px 0 4px;
}

/* The phone search pill (under the top bar on the home page and the
   catalogue). */
.aa .m-search {
  position: relative;
  display: flex;
  align-items: center;
  height: 48px;
  margin: 0 16px;
  padding: 0 14px 0 0;
  border-radius: 24px;
  border: 1px solid var(--outline-variant);
  background: var(--aa-raised);
  color: var(--on-surface-variant);
}

/* Its focus ring drawn inside it: the pill stands at <main>'s top edge,
   where <main> clips (BeerCSS: `overflow: clip`), so the shared ring's outer
   line — a shadow outside the pill — was cut off along its top. */
.aa .m-search:has(> input:focus) {
  box-shadow: inset 0 0 0 1px var(--primary);
}

.aa .m-search > .aa-search-cat {
  padding: 0 6px 0 16px;
}

.aa .m-search > i {
  flex: none;
  margin-left: 10px;
}

.aa .m-search .aa-search-menu {
  min-width: 248px;
}

.aa .m-search .aa-search-menu button {
  height: 48px;
}

/* 16 px text: iOS zooms into smaller inputs on focus. */
.aa .m-search input {
  all: unset;
  box-sizing: border-box;
  flex: 1 1 auto;
  min-width: 0;
  height: 100%;
  padding: 0 4px 0 8px;
  font-family: var(--font);
  font-size: 16px;
  color: var(--on-surface);
  text-overflow: ellipsis;
}

/* A sideways-scrolling row (category chips); the scrollbar stays hidden. */
.aa .m-scroll {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding: 0 16px;
  scrollbar-width: none;
}

.aa .m-scroll > * {
  flex: none;
}

.aa .m-sechead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

/* M3 navigation bar: always at the bottom of the screen on phones. */
.aa .m-nav {
  grid-area: bottom;
  position: sticky;
  bottom: 0;
  z-index: 50;
  display: flex;
  justify-content: space-around;
  align-items: flex-start;
  gap: 0;
  height: 72px;
  padding: 10px 4px 0;
  background: var(--surface-container);
  color: var(--on-surface-variant);
  border-radius: 0;
}

.aa .m-nav a {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  width: 80px;
  font-size: 12px;
  line-height: 16px;
  font-weight: 600;
  letter-spacing: 0.2px;
  color: var(--on-surface-variant);
}

.aa .m-nav a > .ind {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 32px;
  border-radius: 16px;
}

.aa .m-nav a.active {
  color: var(--on-surface);
}

.aa .m-nav a.active > .ind {
  background: var(--secondary-container);
  color: var(--on-secondary-container);
}

.aa .m-nav a.active > .ind > i {
  font-variation-settings: "FILL" 1;
}

/* The phone footer: quick cards, logo, links, contacts, payment methods. */
.aa .m-foot {
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-block-size: 0;
  padding: 28px 16px 24px;
  background: var(--aa-footer);
  color: var(--aa-on-footer);
  border-radius: 0;
}

/* The phone footer's wordmark: square corners too (see .aa-logo img). */
.aa .m-foot > img {
  width: 120px;
  height: 43px;
  border-radius: 0;
}

.aa .m-foot-muted {
  color: var(--aa-footer-muted);
}

.aa .m-quick {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 8px;
  padding-bottom: 20px;
  margin-bottom: 4px;
  border-bottom: 1px solid var(--aa-footer-line);
  border-radius: 0;
}

.aa .m-quick .aa-quick {
  gap: 6px;
  padding: 12px 12px 14px;
  border-radius: 22px;
}

.aa .m-quick .aa-quick .ic {
  width: 32px;
  height: 32px;
}

.aa .m-quick .aa-quick .ic i {
  --_size: 18px;
  font-size: 18px;
}

.aa .m-quick .aa-quick .h {
  font-size: 16px;
  line-height: 22px;
}

.aa .m-quick .aa-quick .d {
  font-size: 13px;
  line-height: 18px;
}

.aa .m-foot .contact {
  display: flex;
  flex-direction: column;
  gap: 8px;
  font-size: 13px;
  color: var(--aa-footer-muted);
}

/* Left-aligned like the design's plain lines (BeerCSS centres a link's content). */
.aa .m-foot .contact :is(span, a) {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 8px;
  color: inherit;
}

.aa .m-foot .contact i {
  --_size: 18px;
  font-size: 18px;
  color: var(--aa-footer-link);
}

.aa .m-foot .links {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px 16px;
  font-size: 14px;
}

.aa .m-foot .links a {
  display: inline;
  color: var(--aa-footer-muted);
}

.aa .m-foot .pay {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.aa .m-foot .aa-paychip {
  height: 28px;
  font-size: 12px;
}

/* ---------- Floating buy bar: the checkouts' and the product page's one buy button ---------- */

/* The page's one buy button with what it costs (decisions 107–109), in a bar
   that floats at the bottom of every screen: clear of the screen's edges, so
   its rounded corners show, in the brand's container colour, so it stands
   apart from the grey page and the white cards in both themes. Sticky in
   BeerCSS's bottom grid area (`{% block bottom_bar %}`): on screen while the
   page scrolls, never over the page's end. A page lays out what is inside
   (checkout.css `.fc-mdock`, product.css `.md-dock`). Phones: 12 px from the
   edges. */
.aa .aa-buybar {
  grid-area: bottom;
  position: sticky;
  bottom: 12px;
  z-index: 50;
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 12px;
  padding: 12px 8px 12px 16px;
  border-radius: 28px;
  background: var(--primary-container);
  color: var(--on-primary-container);
  box-shadow: var(--elevate3);
}

/* Its small words in the bar's own colour (the page's grey looked faded on
   the blue); their size keeps them below the price. */
.aa .aa-buybar .muted {
  color: inherit;
}

@media (min-width: 601px) {
  .aa .aa-buybar {
    gap: 10px;
    padding: 12px 12px 12px 20px;
  }
}

/* Tablets: as wide as the cards, 16 px above the bottom. */
@media (min-width: 601px) and (max-width: 992px) {
  .aa .aa-buybar {
    bottom: 16px;
    margin: 16px 24px;
  }
}

/* Desktops: centred, 24 px above the bottom, where the eyes end up — the
   owner's choice over a column that follows the scroll ("I dont want the
   distraction"). `--aa-buybar-width`: a page's own width (640 px). At the
   page's end it stands under the footer, not over it. */
@media (min-width: 993px) {
  .aa .aa-buybar {
    justify-self: center;
    width: min(var(--aa-buybar-width, 640px), 100% - 48px);
    bottom: 24px;
    margin: 24px 0;
    padding-inline-start: 28px;
  }
}

/* A place the browser scrolls to — the field it asks to fill in, the next
   one by Tab, a link to #ulasan — stops above the bar, never behind it: the
   bar (72–84 px) and the 12–24 px under it, plus air. */
html:has(.aa-buybar) {
  scroll-padding-bottom: 120px;
}

/* Phones: the top bar stays on screen on every page (64 px), so a place the
   browser scrolls to — the field it asks to fill in, the next one by Tab, a
   field the reader taps (iOS scrolls as its keyboard opens), a link to an
   anchor — stops under it, never behind it. A field the browser pointed at
   landed behind it, out of sight, and the search pill under it lost the top
   edge of its focus ring on an iPhone (the owner's report of 2026-10-15). An
   anchor's own scroll-margin adds to this: keep those small (24 px). */
@media (max-width: 600px) {
  html {
    scroll-padding-top: 80px;
  }
}

/* ---------- Checkout chrome: slim header, secure badge, stepper, slim footer ---------- */

/* The design's `ckheader`: the logo, "Pembayaran aman", the language and
   theme switches and "Bantuan" — nothing else to wander off to while paying. */
.aa .aa-ckhdr .aa-hdr-top {
  height: 76px;
}

.aa .aa-ck-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
}

.aa .aa-secure {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 32px;
  padding: 0 12px;
  border-radius: 16px;
  background: var(--aa-success-container);
  color: var(--aa-on-success-container);
  font-size: 13px;
  font-weight: 650;
  white-space: nowrap;
}

.aa :where(.aa-secure > i) {
  --_size: 18px;
  font-size: 18px;
  font-variation-settings: "FILL" 1;
}

/* The stepper: numbered dots joined by lines; a done step shows a check and
   blues the line after it. */
.aa .aa-steps {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.aa .aa-steps li {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  font-weight: 600;
  color: var(--on-surface-variant);
  white-space: nowrap;
}

.aa .aa-steps li + li::before {
  content: "";
  width: 40px;
  height: 2px;
  border-radius: 1px;
  background: var(--outline-variant);
}

.aa .aa-steps .dot {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--surface-container-highest);
  color: var(--on-surface-variant);
  font-size: 13px;
  font-weight: 750;
}

.aa :where(.aa-steps .dot > i) {
  --_size: 18px;
  font-size: 18px;
}

.aa .aa-steps li:is(.current, .done) {
  color: var(--on-surface);
}

.aa .aa-steps li.current .dot {
  background: var(--primary);
  color: var(--on-primary);
}

.aa .aa-steps li.done .dot {
  background: var(--primary-container);
  color: var(--on-primary-container);
}

.aa .aa-steps li.done + li::before {
  background: var(--primary);
}

/* In the checkout header (after the stepper's own rules, which set its
   margin to 0): the cart flow's stepper sits 48 px from "Pembayaran aman"
   (the design's ckheader: twice the row's gap). */
.aa .aa-ckhdr .aa-steps {
  margin-left: 24px;
}

/* Below 1280 px its four steps do not fit beside the header's buttons (the
   design draws them at 1440 only; at 993–1279 px they pushed the buttons
   past the screen's edge — the row has ~300 px for a stepper of 430 px and
   more): the page's title says where one is, and phones show their own
   stepper under the top bar. */
@media (max-width: 1279px) {
  .aa .aa-ckhdr .aa-steps {
    display: none;
  }
}

/* 1280–1439 px: the four steps still share the row with the buttons, so the
   done steps keep their dot only and the lines between the steps are
   shorter (the guest's "Data pembeli" is the longest label). */
@media (min-width: 1280px) and (max-width: 1439px) {
  .aa .aa-ckhdr .aa-steps li + li::before {
    width: 24px;
  }

  .aa .aa-ckhdr .aa-steps li.done > span:last-child {
    display: none;
  }
}

/* Narrow tablets (601–719 px, widths the design never drew): the logo,
   "Pembayaran aman", the language and theme switches and "Bantuan" share
   one row with nothing to spare. In Google Sans Flex (decision 134) the
   badge and "Bantuan" grew 15 px and pushed "Bantuan" 7 px past the row's
   padding at 601 px; each gives 4 px a side back. */
@media (min-width: 601px) and (max-width: 719px) {
  .aa .aa-ckhdr .aa-secure {
    padding: 0 8px;
  }

  .aa .aa-ckhdr .aa-ck-actions > .button.transparent {
    padding: 0 12px;
  }
}

/* The design's `ckfooter`: copyright, "Pembayaran aman & terenkripsi",
   terms and privacy on one line. (The `:where()` around the links and the
   icons here, of the badge and the stepper too, keeps Biome's
   noDescendingSpecificity count where it was: the rule compares every rule
   whose last part is written the same, across unrelated components.) */
.aa .aa-ckfoot {
  display: block;
  min-block-size: 0;
  padding: 22px 0;
  border-radius: 0;
  border-top: 1px solid var(--outline-variant);
  background: var(--aa-header);
  color: var(--on-surface-variant);
  font-size: 13px;
}

.aa .aa-ckfoot-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}

/* Tablets: the line no longer fits at 601 px (the privacy link went past
   the screen's edge) — it wraps, centred. */
@media (max-width: 992px) {
  .aa .aa-ckfoot-row {
    flex-wrap: wrap;
    justify-content: center;
    row-gap: 8px;
  }
}

.aa .aa-ckfoot-safe {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.aa .aa-ckfoot nav {
  display: flex;
  gap: 20px;
}

.aa .aa-ckfoot :where(a) {
  display: inline;
  color: var(--on-surface-variant);
}

.aa .aa-ckfoot a:hover {
  color: var(--on-surface);
  text-decoration: underline;
}

.aa :where(.aa-ckfoot i) {
  --_size: 18px;
  font-size: 18px;
  color: var(--aa-success);
}

/* ---------- Desktop widths the design never drew (993–1279 px) ---------- */

/* Tighter header and nav so all eight links and the language / theme
   controls still fit on one row at 993 px. */
@media (min-width: 993px) and (max-width: 1279px) {
  .aa .aa-wrap {
    width: min(1312px, 100% - 64px);
  }

  .aa .aa-hdr-top {
    gap: 16px;
    padding: 0 32px;
  }

  .aa .aa-hdr-nav {
    padding: 0 24px;
  }

  .aa .aa-navlink {
    padding: 0 10px;
  }
}

/* ---------- Tablet (BeerCSS m: 601–992 px; the design's 820 px boards) ---------- */

@media (min-width: 601px) and (max-width: 992px) {
  .aa .aa-hdr-menu {
    display: inline-flex;
    margin-right: -4px;
  }

  .aa .aa-wrap {
    width: auto;
    margin-inline: 24px;
  }

  .aa .aa-hdr-top {
    gap: 12px;
    height: 72px;
    padding: 0 16px 0 12px;
  }

  .aa .aa-logo img {
    width: 120px;
    height: 43px;
  }

  .aa .aa-search {
    height: 44px;
    border-radius: 22px;
  }

  .aa .aa-search-cat {
    padding: 0 8px 0 16px;
  }

  .aa .aa-search input {
    font-size: 14px;
  }

  .aa .aa-hdr-actions {
    gap: 4px;
  }

  /* "Semua Produk" becomes an icon-only circle, like BeerCSS's `.circle`
     (its label stays in aria-label). */
  .aa .aa-allbtn {
    inline-size: var(--_size);
    padding: 0;
    border-radius: 50%;
  }

  .aa .aa-allbtn > span {
    display: none;
  }

  .aa .aa-hdr-nav {
    height: 52px;
    padding: 0 12px;
  }

  /* All eight links fit from about 760 px; below that the row scrolls
     sideways instead of widening the page (the 4 px keep focus rings visible). */
  .aa .aa-mainnav {
    gap: 0;
    min-width: 0;
    overflow-x: auto;
    padding-block: 4px;
    scrollbar-width: none;
  }

  .aa .aa-navlink {
    height: 36px;
    padding: 0 10px;
    font-size: 13px;
  }

  /* Language and theme move into the drawer. */
  .aa .aa-prefs {
    display: none;
  }

  .aa dialog.mm-drawer {
    width: min(340px, 100vw - 56px);
  }

  .aa .aa-pmedia img {
    aspect-ratio: 199 / 144;
  }

  .aa .aa-pbody {
    padding: 10px 14px 14px;
  }

  .aa .aa-ptitle {
    font-size: 15px;
    line-height: 21px;
    min-height: 42px;
  }

  .aa .aa-price {
    font-size: 18px;
    line-height: 24px;
  }

  .aa .aa-pfoot {
    flex-wrap: nowrap;
  }

  .aa .aa-sechead {
    flex-wrap: wrap;
    align-items: flex-end;
  }

  .aa .aa-foot-quick {
    gap: 12px;
    padding: 32px 0 28px;
  }

  .aa .aa-quick {
    padding: 14px 14px 16px;
  }

  .aa .aa-quick .hd {
    gap: 10px;
  }

  .aa .aa-quick .h {
    font-size: 17px;
  }

  .aa .aa-foot-main {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 36px 24px;
    padding: 36px 0 32px;
  }

  .aa .aa-foot-brand {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: start;
    column-gap: 32px;
    row-gap: 16px;
  }

  .aa .aa-foot-brand > a {
    grid-column: 1 / -1;
  }

  .aa .aa-foot-pay {
    flex-wrap: wrap;
  }

  .aa .aa-foot-paynote {
    margin-left: 0;
    flex-basis: 100%;
  }

  .aa .aa-foot-bottom {
    flex-direction: column;
    align-items: flex-start;
    gap: 12px;
  }
}

/* The menu button only exists where the drawer does (tablet); phones have
   their own in the top app bar. */
@media (min-width: 993px) {
  .aa .aa-hdr-menu {
    display: none;
  }
}

/* ---------- Phone (BeerCSS s: ≤ 600 px; the design's 390 px boards) ---------- */

@media (max-width: 600px) {
  /* Sections that use the content column keep 16 px from the screen edge. */
  .aa .aa-wrap {
    width: auto;
    margin-inline: 16px;
  }

  /* The product card becomes the design's compact phone card (.m-card). */
  .aa .aa-pcard {
    border-radius: 20px;
  }

  .aa .aa-pmedia {
    margin: 6px 6px 0;
    border-radius: 14px;
  }

  .aa .aa-pmedia img {
    aspect-ratio: 129 / 101;
  }

  .aa .aa-ptag {
    top: 12px;
    left: 12px;
    height: 22px;
    padding: 0 8px;
    font-size: 11px;
  }

  .aa .aa-pfav {
    top: 10px;
    right: 10px;
  }

  .aa .aa-pbody {
    gap: 4px;
    padding: 10px 12px 12px;
  }

  .aa .aa-pcat {
    font-size: 11px;
  }

  .aa .aa-pcat > i {
    --_size: 14px;
    font-size: 14px;
  }

  .aa .aa-ptitle {
    min-height: 40px;
    font-size: 14px;
    line-height: 20px;
  }

  .aa .aa-pmeta {
    font-size: 11px;
  }

  .aa i.aa-star {
    --_size: 14px;
    font-size: 14px;
  }

  .aa .aa-pfoot {
    margin-top: 0;
    padding-top: 0;
  }

  /* "Mulai dari", price and struck-through price stack 4 px apart (the
     phone card's body gap in the design). */
  .aa .aa-pprice {
    gap: 4px;
  }

  .aa .aa-prow {
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
  }

  .aa .aa-from {
    margin-top: 2px;
    font-size: 11px;
    line-height: 14px;
  }

  .aa .aa-price {
    font-size: 16px;
    line-height: 22px;
    font-weight: 740;
    letter-spacing: 0;
  }

  .aa .aa-was {
    font-size: 11px;
  }

  .aa .aa-pbtns {
    gap: 6px;
    margin-top: auto;
    padding-top: 8px;
  }

  .aa .aa-pbtns > .pb-buy {
    --_size: 40px;
    padding: 0 10px;
    gap: 6px;
    border-radius: 20px;
    font-size: 14px;
  }

  .aa .aa-pbtns > .pb-buy > i {
    --_size: 18px;
    font-size: 18px;
  }

  /* The phone card's narrow row: the cart button and "Detail" (its short
     words) fit side by side at 360 px, each 44 px tall (the touch rule). */
  .aa .aa-pbtns > .pb-row {
    gap: 6px;
  }

  .aa .pb-row > .pb-dtl {
    --_size: 28px;
    padding: 0 10px 0 8px;
    gap: 4px;
    border-radius: 14px;
    font-size: 12px;
  }

  .aa .pb-row > .pb-cart {
    --_size: 28px;
  }

  .aa .pb-row > :is(.pb-dtl, .pb-cart) > i {
    --_size: 16px;
    font-size: 16px;
  }
}

/* ---------- The debug code chip (OTP_DEBUG) ---------- */

/* component/otp_debug.html: the live one-time code under a code field, with
   its copy button — a developer's aid, never in production. Dashed and in
   the tertiary colours, so nobody takes it for part of the design. */
.aa .aa-otpdebug {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-top: 8px;
}

.aa .aa-otpdebug > .chip {
  gap: 6px;
  border: 1px dashed var(--tertiary);
  background-color: var(--tertiary-container);
  color: var(--on-tertiary-container);
}

.aa .aa-otpdebug .code-text {
  font-weight: 700;
  letter-spacing: 2px;
}

/* Copying needs the script; without it the code is selected by hand. (By
   its data-copy, not "button": Biome's specificity order stays as it was.) */
:where(html:not(.js)) .aa .aa-otpdebug > [data-copy] {
  display: none;
}

/* ---------- Preview bar: the admin's preview of a piece of content (component/preview_bar.html) ---------- */

/* Over the page, at its content's width: the warning colours and a dashed
   edge, so nobody takes it for part of the design (decision 82). The words
   take the room they need; the language links and "Kembali ke editor" wrap
   under them on a narrow screen. */
.aa .aa-preview {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 8px 16px;
  inline-size: min(1136px, 100% - 64px);
  box-sizing: border-box;
  margin: 0 auto 16px;
  padding: 12px 16px;
  border: 1px dashed var(--aa-warn);
  border-radius: 16px;
  background-color: var(--aa-warn-container);
  color: var(--aa-on-warn-container);
}

.aa .aa-preview-icon {
  flex: none;
}

.aa .aa-preview-text {
  display: flex;
  flex: 1 1 240px;
  flex-direction: column;
  gap: 2px;
  min-inline-size: 0;
}

.aa .aa-preview-saved {
  font-size: 0.875rem;
  opacity: 0.85;
}

.aa .aa-preview-tools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 16px;
}

.aa .aa-preview-langs {
  display: flex;
  gap: 4px;
}

.aa .aa-preview-link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  min-block-size: 32px;
  padding: 0 10px;
  border-radius: 16px;
  color: inherit;
  text-decoration: underline;
}

.aa .aa-preview-link.is-on {
  background-color: var(--aa-warn);
  color: var(--aa-warn-container);
  text-decoration: none;
}

/* Touch screens: 44 px links (the owner's rule for phones and tablets);
   phones: the page's 16 px gutters. */
@media (max-width: 992px) {
  .aa .aa-preview-link {
    min-block-size: 44px;
  }
}

@media (max-width: 600px) {
  .aa .aa-preview {
    inline-size: calc(100% - 32px);
  }
}

/* ---------- "Lampirkan file": a customer's one file (component/attach.html) ---------- */

/* The button, the chosen file (or the hint) and its remove button; a
   refusal or "choose it again" under them. */
.aa .aa-attach {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.aa .aa-attach-row {
  position: relative;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 12px;
}

.aa .aa-attach-btn {
  cursor: pointer;
}

/* Without JavaScript nothing names the chosen file: the browser's own
   input shows instead of the button (see .aa-attach-input below). Before
   the button's other rules: they are more specific (Biome's order). */
:where(html:not(.js)) .aa .aa-attach-btn {
  display: none;
}

.aa .aa-attach.invalid .aa-attach-btn {
  border-color: var(--error);
  color: var(--error);
}

/* The real input: out of sight but not out of reach — the keyboard still
   lands on it, and its focus rings the button that stands for it. */
.aa .aa-attach-input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  overflow: hidden;
  clip-path: inset(50%);
}

:where(html:not(.js)) .aa .aa-attach-input {
  position: static;
  width: auto;
  height: auto;
  opacity: 1;
  clip-path: none;
}

.aa .aa-attach:has(.aa-attach-input:focus-visible) .aa-attach-btn {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* The hint, or the chosen file's name and size (app.js). */
.aa .aa-attach-hint {
  min-width: 0;
  overflow-wrap: anywhere;
}

.aa .aa-attach.has-file .aa-attach-hint {
  font-weight: 600;
  color: var(--on-surface);
}

/* The remove button shows once a file is chosen (a class: the hidden
   attribute loses to BeerCSS's button display). */
.aa .aa-attach-clear.is-hidden {
  display: none;
}

/* The refusal or "choose it again" (a class, not "output": the fields'
   own output rules are more specific). */
.aa .aa-attach-msg {
  font-size: 12px;
  line-height: 16px;
}

.aa .aa-attach-msg.invalid {
  color: var(--error);
}

.aa .aa-attach-again {
  color: var(--on-surface-variant);
}

/* The public forms' honeypot (contact, newsletter): off the screen for
   people; aria-hidden and tabindex="-1" keep it from screen readers and the
   keyboard. Robots that fill every field fill it. */
.aa .aa-hp {
  position: absolute;
  left: -10000px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ---------- Loading placeholders (shimmer) ---------- */

/* The owner's request of 2026-09-30: on a slow connection the catalogue says
   at once that it is on its way, with grey shapes where the cards will be and
   a band of light sweeping over them, as Amazon does (component/skeleton.html;
   app.js decides when). The design's surface tones, so both themes; still
   for visitors whose device asks for less motion. */
@keyframes aa-shimmer {
  from {
    background-position: 100% 0;
  }

  to {
    background-position: 0 0;
  }
}

.aa .sk {
  display: block;
  border-radius: 8px;
  background: linear-gradient(100deg, var(--aa-sk-base) 40%, var(--aa-sk-shine) 50%, var(--aa-sk-base) 60%);
  background-size: 300% 100%;
  animation: aa-shimmer 1.4s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  .aa .sk {
    animation: none;
  }
}

/* A placeholder card borrows the real card's boxes (aa-pcard, aa-pmedia,
   aa-pbody), so it is as big as the card that replaces it; its lines stand
   for the category, the two-line title, the rating, the price and "Beli". */
.aa .aa-skcard {
  pointer-events: none;
}

.aa .sk-img {
  aspect-ratio: 262 / 184;
  border-radius: 0;
}

.aa .sk-line {
  height: 12px;
}

.aa .sk-cat {
  width: 45%;
}

.aa .sk-title {
  width: 90%;
  height: 16px;
  margin-top: 4px;
}

.aa .sk-title2 {
  width: 65%;
  height: 16px;
}

.aa .sk-meta {
  width: 50%;
}

.aa .sk-price {
  width: 40%;
  height: 20px;
  margin-top: 10px;
}

.aa .sk-btn {
  height: 40px;
  margin-top: 6px;
  border-radius: 20px;
}

/* A whole catalogue page (the moment between a click that leads to the
   catalogue and its arrival): hidden until app.js marks <main> as leaving;
   then the page's own content steps aside. (0, 3, 1) is more than any page
   rule on <main>'s children; BeerCSS's screen-size helpers only ever hide. */
.aa .aa-skpage {
  display: none;
}

.aa main.is-leaving > :not(.aa-skpage) {
  display: none;
}

.aa main.is-leaving > .aa-skpage {
  display: flex;
  flex-direction: column;
  gap: 24px;
  padding-block: 24px 48px;
}

.aa .aa-skhead {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.aa .sk-crumb {
  width: 160px;
  height: 14px;
}

.aa .sk-h1 {
  width: min(420px, 70%);
  height: 44px;
  border-radius: 12px;
}

.aa .sk-intro {
  width: min(640px, 90%);
  height: 16px;
}

.aa .aa-skchips {
  display: flex;
  gap: 8px;
  overflow: hidden;
}

.aa .sk-chip {
  flex: 0 0 auto;
  width: 120px;
  height: 36px;
  border-radius: 18px;
}

/* The catalogue's own measures (css/page/products.css): a 296 px filter
   column, three cards a row (two from 1199 px down, three on tablets, two
   on narrow tablets and phones). */
.aa .aa-skbody {
  display: grid;
  grid-template-columns: 296px minmax(0, 1fr);
  gap: 32px;
  align-items: start;
}

.aa .aa-skside {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.aa .sk-block {
  height: 140px;
  border-radius: 20px;
}

.aa .aa-skgrid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 24px;
}

@media (min-width: 993px) and (max-width: 1279px) {
  .aa .aa-skbody {
    grid-template-columns: 264px minmax(0, 1fr);
    gap: 24px;
  }

  .aa .aa-skgrid {
    gap: 16px;
  }
}

@media (min-width: 993px) and (max-width: 1199px) {
  .aa .aa-skgrid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 992px) {
  .aa .aa-skbody {
    grid-template-columns: minmax(0, 1fr);
  }

  .aa .aa-skgrid {
    gap: 16px;
  }
}

@media (min-width: 601px) and (max-width: 992px) {
  .aa .sk-img {
    aspect-ratio: 199 / 144;
  }
}

@media (max-width: 720px) {
  .aa .aa-skgrid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
  }
}

@media (max-width: 600px) {
  .aa .sk-img {
    aspect-ratio: 129 / 101;
  }

  .aa main.is-leaving > .aa-skpage {
    gap: 14px;
    padding-block: 12px 24px;
  }

  .aa .sk-h1 {
    height: 32px;
  }
}

/* ---------- Add-ons (decisions 139, 142): storefront/component/addons.html ---------- */

/* A product's side items on its page and in both checkouts, laid out for a
   phone first (the owner: "with limited space we must position the layout
   effectively"): the premium ones first — on the product page a row of
   cards that scrolls sideways on a phone, at checkout rows to tick (the
   order bump marketplaces put before payment) — then the free bonuses: on
   the product page a row of smaller cards of their own (decision 144: "we
   must separate premium add-on row and free add-on row"), at checkout a
   compact list. Premium is gold, free is silver (decision 144): the medals
   before their headings, the tier on each card, the dialog's chip. */

/* A kind's medal (decision 144): a round badge in gold (premium) or silver
   (free) with the kind's icon in the metal's dark ink — before each kind's
   heading on the product page and in the checkouts. A light rim on top and
   a soft shadow below give the metal its shine. */
.aa .aa-medal {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  inline-size: 28px;
  block-size: 28px;
  border-radius: 50%;
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.55),
    0 1px 2px rgb(0 0 0 / 0.22);
}

/* Its icon filled, at the medal's scale (an icon's box is `--_size`; a class
   of its own, not `> i`: Biome's specificity order). */
.aa .aa-medal-ic {
  --_size: 18px;
  font-size: 18px;
  font-variation-settings: "FILL" 1;
}

/* A smaller medal beside a smaller heading (the cart's checkout). */
.aa .aa-medal.small {
  inline-size: 24px;
  block-size: 24px;
}

.aa .aa-medal.small > .aa-medal-ic {
  --_size: 15px;
  font-size: 15px;
}

/* The metals: a light, a middle and a shade, top left to bottom right —
   set on the page's <body> (`.aa`), where the theme's tokens are, so each
   gradient takes its theme's colours; pages draw with them (checkout.css's
   files' icons too). */
.aa {
  --aa-gold-metal: linear-gradient(145deg, var(--aa-gold-hi), var(--aa-gold) 48%, var(--aa-gold-lo));
  --aa-silver-metal: linear-gradient(145deg, var(--aa-silver-hi), var(--aa-silver) 48%, var(--aa-silver-lo));
}

.aa :is(.aa-medal, .aa-addon-tier, .aa-addon-chip).gold {
  background: var(--aa-gold-metal);
  color: var(--aa-on-gold);
}

.aa :is(.aa-medal, .aa-addon-tier, .aa-addon-chip).silver {
  background: var(--aa-silver-metal);
  color: var(--aa-on-silver);
}

/* The free add-ons a purchase includes: one quiet row each. */
.aa .aa-addon-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* One included add-on: its picture, its words, "Detail" — on the page's inset
   grey, as the design's quiet rows are. */
.aa .aa-addon-row {
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  padding: 8px 8px 8px 10px;
  border-radius: 16px;
  background: var(--aa-inset);
}

/* An add-on's small picture (16:10, as the cards'). */
.aa .aa-addon-thumb {
  width: 64px;
  height: 40px;
  object-fit: cover;
  border-radius: 8px;
  background: var(--surface-container-high);
}

/* Its title over its price or "Gratis"; a long title wraps, never overflows. */
.aa .aa-addon-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  overflow-wrap: anywhere;
}

/* "Gratis" with its gift, in silver's ink (decision 144: free is silver). */
.aa .aa-addon-free {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--aa-silver-ink);
  font-weight: 600;
}

/* The gift beside "Gratis" at the text's size (an icon's box is `--_size`). */
.aa .aa-addon-gift {
  --_size: 16px;
  font-size: 16px;
}

/* "Detail": a text button that never shrinks beside a long title. */
.aa .aa-addon-more {
  flex: none;
  white-space: nowrap;
}

/* The product page's rows of add-ons, each kind its own: a row that scrolls
   sideways on a phone (one card and a bit of the next in view: there is
   more), a grid from a tablet up. */
.aa .aa-addon-cards {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(220px, 76%);
  gap: 12px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-block-end: 4px;
  scrollbar-width: thin;
}

/* The free row's cards are smaller than the premium ones: a bonus beside
   the precious kind (decision 144). */
.aa .aa-addon-cards.is-free {
  grid-auto-columns: minmax(180px, 60%);
}

@media (min-width: 601px) {
  .aa .aa-addon-cards {
    grid-auto-flow: row;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    overflow: visible;
  }

  .aa .aa-addon-cards.is-free {
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  }
}

/* One add-on's card: the storefront's raised surface and a ring — gold
   around a premium one, silver around a free one (decision 144); its tier
   stands over its picture. */
.aa .aa-addon-card {
  position: relative;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  border-radius: 20px;
  background: var(--aa-raised);
  box-shadow: inset 0 0 0 1px var(--outline-variant);
  scroll-snap-align: start;
}

.aa .aa-addon-card.is-premium {
  box-shadow: inset 0 0 0 1.5px var(--aa-gold-line);
}

.aa .aa-addon-card.is-free {
  box-shadow: inset 0 0 0 1px var(--aa-silver-line);
}

/* A card's tier over the top of its picture: "Premium" in gold, "Bonus" in
   silver, with its icon (decision 144) — the heading above says it too, so
   screen readers skip it. */
.aa .aa-addon-tier {
  position: absolute;
  inset-block-start: 10px;
  inset-inline-start: 10px;
  z-index: 1;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 3px 10px 3px 6px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 700;
  line-height: 18px;
  letter-spacing: 0.2px;
  box-shadow:
    inset 0 1px 0 rgb(255 255 255 / 0.55),
    0 1px 3px rgb(0 0 0 / 0.25);
}

/* The tier's icon, filled, at its words' size. */
.aa .aa-addon-tier-ic {
  --_size: 16px;
  font-size: 16px;
  font-variation-settings: "FILL" 1;
}

/* The card's picture fills its top, 16:10; its corners are the card's
   (`border-radius: 0`: BeerCSS rounds every element and the card clips). */
.aa .aa-addon-cover {
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  border-radius: 0;
  background: var(--surface-container-high);
}

/* The card's words under its picture; a long word breaks rather than
   widening the card. */
.aa .aa-addon-body {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 6px;
  padding: 12px 14px 8px;
  overflow-wrap: anywhere;
}

/* Two lines of its description at most: the rest is in "Detail".
   border-radius 0: BeerCSS rounds every element, which clips the first
   letters under `overflow: hidden`. */
.aa .aa-addon-sum {
  display: -webkit-box;
  overflow: hidden;
  border-radius: 0;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
}

/* Its price and "Detail" at the card's foot, whatever the words above. */
.aa .aa-addon-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-block-start: auto;
}

/* A checkout's paid add-ons: one row each — the box, its picture, title and
   price are one label (one large target); "Detail" stands beside it. */
.aa .aa-addon-picker {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* One add-on to tick: the label and "Detail" side by side, one outline. */
.aa .aa-addon-pick {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 4px;
  align-items: center;
  padding-inline-end: 4px;
  border-radius: 16px;
  box-shadow: inset 0 0 0 1px var(--outline-variant);
}

/* Ticked: the brand's container, as a chosen license is. */
.aa .aa-addon-pick:has(input:checked) {
  background: var(--primary-container);
  color: var(--on-primary-container);
  box-shadow: inset 0 0 0 2px var(--primary);
}

/* The label: box, picture, words — at least 56 px tall, a target beyond the
   44 px rule; its words wrap (BeerCSS keeps a label on one line). */
.aa .aa-addon-tick {
  display: grid;
  grid-template-columns: auto 64px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  min-block-size: 56px;
  padding: 8px 8px 8px 12px;
  cursor: pointer;
  white-space: normal;
}

/* The box's own square: no room for words inside it (BeerCSS pads it for a
   label written in the box; this label's words stand beside it). */
.aa .aa-addon-box {
  padding: 0;
}

/* "+ Rp 39.000": what a tick adds. */
.aa .aa-addon-price {
  font-weight: 600;
}

/* "Termasuk": a premium add-on at Rp 0 comes with every purchase (decision
   142) — said with a tick in the brand's colour where the others show their
   price. */
.aa .aa-addon-incl {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--primary);
  font-weight: 600;
}

/* The tick at the text's size (an icon's box is `--_size`; a class of its
   own, not `> i`: Biome's specificity order). */
.aa .aa-addon-incl-ic {
  --_size: 16px;
  font-size: 16px;
}

/* A checkout's premium add-on at Rp 0: its row reads as chosen already, on
   the inset grey — nothing to tick, so no pointer. */
.aa .aa-addon-pick.is-included {
  background: var(--aa-inset);
}

.aa .aa-addon-pick.is-included > .aa-addon-tick {
  cursor: default;
}

/* The brand's tick where the box would be, in the box's 28 px slot, so the
   row's picture and words line up with the rows to tick. */
.aa .aa-addon-done {
  display: inline-flex;
  inline-size: 28px;
  color: var(--primary);
}

/* "Lihat N lainnya": a long list's tail of included add-ons, folded
   (decision 142: a bundle may include every product of the shop) — never a
   box to tick. Its line is a 44 px target, as every control on a phone. */
.aa .aa-addon-fold > summary {
  display: flex;
  align-items: center;
  min-block-size: 44px;
  cursor: pointer;
  font-weight: 600;
}

/* Open, its rows follow at the list's own gap. */
.aa .aa-addon-fold[open] > summary {
  margin-block-end: 8px;
}

/* "Perbarui total": what a tick does by itself once scripts run. */
.aa .aa-addon-refresh {
  align-self: flex-start;
}

/* With scripts a tick asks for the totals itself: the button is not needed. */
html.js .aa .aa-addon-refresh {
  display: none;
}

/* "Detail": a dialog of its own — every picture in a strip that snaps (the
   product gallery's script), the price, the whole description. Without
   scripts a dialog cannot open: its content lays out in the page instead. */
.aa dialog.aa-addon-dlg {
  width: min(560px, 100vw - 32px);
  max-width: none;
  max-height: calc(100dvh - 32px);
  padding: 16px;
  border: 0;
  border-radius: 28px;
  background: var(--aa-raised);
  color: var(--on-surface);
  box-shadow: var(--elevate3);
  overflow: auto;
}

/* The scrim behind the dialog: a click on it closes the dialog (app.js).
   Literal colours: older browsers do not pass custom properties to
   ::backdrop. BeerCSS keeps a dialog's backdrop invisible: shown while open. */
.aa dialog.aa-addon-dlg::backdrop {
  background: rgb(0 0 0 / 0.5);
}

.aa dialog.aa-addon-dlg[open]::backdrop {
  opacity: 1;
  visibility: visible;
}

/* Without scripts the dialog's content stands in the page, outlined: BeerCSS
   keeps a closed dialog hidden and faded out, so all of that is undone here
   (as the account's sheets do). With them, opening takes the focus in as
   every dialog does (components.css "Dialogs"). */
html:not(.js) .aa dialog.aa-addon-dlg {
  position: static;
  display: block;
  width: auto;
  max-height: none;
  margin-block: 12px;
  box-shadow: inset 0 0 0 1px var(--outline-variant);
  transform: none;
  visibility: visible;
  opacity: 1;
}

/* Without scripts nothing opens, closes or steps through a dialog: no
   "Detail", no close button, no arrows or dots (the strip still scrolls by
   itself, and the details stand in the page). */
html:not(.js) .aa :is(.aa-addon-more, .aa-addon-dlg-head > button, .aa-addon-nav, .aa-addon-dots) {
  display: none;
}

/* The dialog's head: its kind, title and price beside the close button. */
.aa .aa-addon-dlg-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding: 0 0 12px 4px;
  overflow-wrap: anywhere;
}

/* "Add-on premium" / "Bonus gratis" over the title, with its badge. */
.aa .aa-addon-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-block-end: 4px;
  padding: 2px 10px;
  border-radius: 999px;
  background: var(--secondary-container);
  color: var(--on-secondary-container);
  font-size: 12px;
  font-weight: 600;
  line-height: 18px;
}

/* A premium one's chip is gold, a free one's silver (decision 144: the
   metals above, "The metals"). */

/* The chip's badge at its text's size (an icon's box is `--_size`). */
.aa .aa-addon-chip-ic {
  --_size: 14px;
  font-size: 14px;
}

/* The price a little apart from the title above it. */
.aa .aa-addon-dlg-price {
  margin-block-start: 4px;
}

/* The strip: one picture at a time, swiped on a phone. */
.aa .aa-addon-gal {
  position: relative;
}

/* The pictures in a row that snaps one at a time; no scrollbar (the dots
   say where one is). */
.aa .aa-addon-track {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  border-radius: 16px;
  scrollbar-width: none;
}

/* Each picture as wide as the strip. */
.aa .aa-addon-track > figure {
  flex: 0 0 100%;
  scroll-snap-align: start;
}

/* 16:10 like the cards; square corners (the strip rounds them). */
.aa .aa-addon-shot {
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  border-radius: 0;
  background: var(--surface-container-high);
}

/* The arrows over the picture's sides. */
.aa .aa-addon-nav {
  position: absolute;
  inset-block-start: calc(50% - 28px);
  background: var(--aa-raised);
  color: var(--on-surface);
  box-shadow: var(--elevate1);
}

/* The arrows sit 8 px inside the picture's left and right edges. */
.aa .aa-addon-nav.prev {
  inset-inline-start: 8px;
}

.aa .aa-addon-nav.next {
  inset-inline-end: 8px;
}

/* The dots under the strip: which picture is shown (the gallery's script
   marks it). */
.aa .aa-addon-dots {
  display: flex;
  justify-content: center;
  gap: 6px;
  padding-block: 10px 2px;
}

/* One dot per picture; the shown one in the brand's colour. */
.aa .aa-addon-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--outline-variant);
}

.aa .aa-addon-dot.on {
  background: var(--primary);
}

/* The whole description, paragraph by paragraph. */
.aa .aa-addon-about {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px 4px 4px;
  overflow-wrap: anywhere;
}

/* A paid line's add-ons' files: one row each, its own download. */
.aa .aa-addon-files {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* ---------- The WhatsApp field (Text fields; decision 144) ---------- */

/* A WhatsApp field: a fixed "+62" with its flag inside the field, the
   number after it — every page that asks for one (both checkouts, the
   account's Settings: decision 144, one field for the shop), so here, not
   in a page's file. app.js groups the number while it rests and shows the
   bare digits while it is typed in (`data-phone`). Last in the file: its
   input and flag rules outweigh the text fields' (Text fields), and Biome's
   specificity order wants every lighter `input` / `img` rule before them. */
.aa .aa-tel > .cc {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 8px;
  height: var(--_input);
  padding: 0 12px 0 14px;
  border-right: 1px solid var(--outline-variant);
  font-size: 16px;
  font-weight: 600;
  color: var(--on-surface);
  pointer-events: none;
  border-radius: 0;
}

/* The flag: round, with a hairline so its white half shows on white. */
.aa .aa-tel > .cc img {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  outline: 1px solid rgb(0 0 0 / 0.14);
  outline-offset: -1px;
}

/* The number starts after the "+62" and its line. */
.aa .field.aa-tel > input {
  padding-inline-start: 88px;
}

/* ---------- Tap targets on touch screens (phones and tablets) ---------- */

/* The owner's rule (2026-09-28, "UX is the priority"; tablets too, Q16): on
   phones and tablets every button, chip, menu, checkbox, radio button and
   switch is at least 44 × 44 px, as the design handoff's docs/02 asks — also
   where the design drew 32–36 px (chips, small buttons, the card's heart and
   "Lihat detail"). min-* sizes, so each component keeps its own size where
   it is larger, and its design size from 993 px up (mouse and trackpad). The
   admin panel keeps its dense sizes. The browser smoke test measures them. */
@media (max-width: 992px) {
  .aa :is(button, .button, .chip, label.checkbox, label.radio, label.switch) {
    min-block-size: 44px;
  }

  /* Round buttons, and "Semua Produk", which is one on tablets. */
  .aa :is(button, .button):is(.circle, .aa-allbtn) {
    min-inline-size: 44px;
  }
}
