/*
 * site.css — the only stylesheet in this tree that is ours.
 *
 * Everything else under wp-content/ is vendored theme and plugin CSS and must
 * not be edited: it is replaced wholesale whenever the theme updates. This
 * file loads last, so it wins on equal specificity, and it is the place for
 * corrections to the captured design.
 *
 * Keep it small and keep every rule explained.
 */

/* ---------------------------------------------------------------------------
 * The white seam under the navigation.
 *
 * jnews sets `.jeg_content { padding: 30px 0 40px; background: #fff }`. On a
 * normal page that 30px holds the breadcrumb. On a landing page whose first
 * block is a full-bleed hero and which has no breadcrumb, it is 30px of empty
 * white between the black nav and the hero image.
 *
 * The page builder already tried to close it with `margin-top: -32px` on the
 * hero section, which left 28px behind — it cancelled `.entry-header`'s 30px
 * bottom margin but not `.jeg_content`'s 30px top padding. Cancelling spacing
 * with negative margins is how that happened, so this removes the spacing
 * instead, and only where the generator measured it to be empty.
 *
 * All THREE boxes the theme prints above .entry-content have to be zeroed,
 * not just .entry-header. `.jeg_featured` is an empty div carrying
 * `margin-bottom: 30px`, and it alone held 30px of the band open on five of
 * the six pages this was meant to fix — /services/ closed to 1px because it
 * is the one page with no featured slot at all. Measured with
 * `bin/layout.py`, not reasoned about.
 * ------------------------------------------------------------------------ */

.hk-flush-top .jeg_content { padding-top: 0; }
.hk-flush-top .entry-header,
.hk-flush-top .jeg_featured,
.hk-flush-top .jeg_share_top_container { margin-bottom: 0; }

/* The first block sits two wrappers deep:
 *   .entry-content > .content-inner > .wpb-content-wrapper > section.vc_section
 * !important is required — WPBakery writes its per-section rules with it. */
.hk-flush-top .wpb-content-wrapper > .vc_section:first-child,
.hk-flush-top .wpb-content-wrapper > .vc_row:first-child { margin-top: 0 !important; }

/* ---------------------------------------------------------------------------
 * The order button.
 *
 * The WordPress purge removed 169 WooCommerce buy forms, which could not work
 * without a back end. This is what stands in their place: one link to the
 * channel that actually converts. Square, uppercase, 13px at 1px tracking and
 * the leather tan — the same button spec measured off the live site.
 * ------------------------------------------------------------------------ */
.hk-order { margin: 1.5rem 0 2rem; }
.hk-order__btn {
  display: inline-block;
  padding: 0.85rem 1.75rem;
  background: var(--accent);    /* 5.93:1 with white */
  color: var(--paper);
  font-family: var(--sans);
  font-size: var(--t-sm); line-height: 1.2;
  letter-spacing: 1px; text-transform: uppercase;
  text-decoration: none; border-radius: var(--radius);
  transition: background .15s ease;
}
.hk-order__btn:hover, .hk-order__btn:focus-visible { background: var(--accent-deep); color: var(--paper); }

/* ---------------------------------------------------------------------------
 * THE PROSE TYPESET
 *
 * One setting for running text, taken from a blog post — the only page type
 * whose typography is still the original theme's. The 62 written pages were
 * generated and each drifted: 14px body on measures up to 1140px, which is
 * 164 characters per line against a readable band of 45-75.
 *
 * Scope is deliberately narrow: paragraphs, list items and blockquotes inside
 * the content area. Headings, buttons, captions, cards, tables and anything
 * the page builder positions are left alone — this is a reading fix, not a
 * relayout, and a measure applied to a card grid would wreck it.
 *
 * --measure is in em, so it tracks the font size instead of freezing a pixel
 * width that only works at one size.
 * ------------------------------------------------------------------------ */

.hk-typeset .entry-content > p,
.hk-typeset .entry-content .wpb_text_column p,
.hk-typeset .entry-content .wpb_text_column li,
.hk-typeset .entry-content .wpb_text_column blockquote,
.hk-typeset .entry-content .vc_toggle_content p,
.hk-typeset .entry-content .vc_toggle_content li,
.hk-typeset .entry-content .vc_tta-panel-body p {
  font-family: var(--prose);
  font-size: var(--prose-size);
  line-height: var(--prose-lh);
  letter-spacing: var(--prose-ls);
  max-width: var(--measure);
}

/* Colour only where the ground is known to be light. A hero sets white text
   on a photograph; forcing the prose colour there would put #212121 on a dark
   image, which is how contrast bugs get shipped. */
.hk-typeset .entry-content .wpb_text_column:not([style*="color"]) > .wpb_wrapper > p {
  color: var(--prose-fg);
}

/* Inside a narrow builder column, 24px on a 32em measure is wider than the
   column and the size overwhelms it. Step down rather than overflow. */
@media (max-width: 1200px) {
  .hk-typeset .entry-content .wpb_text_column p { font-size: 1.25rem; }
}
.hk-typeset .vc_col-sm-3 p,
.hk-typeset .vc_col-sm-4 p,
.hk-typeset .vc_col-sm-6 p { font-size: 1.0625rem; line-height: 1.6; }

/* A half-width column is ~530px. At 24px that is 44 characters — too tight.
   The measure is what matters, so hold the measure and ease the size. */
.hk-typeset .vc_col-sm-5 p,
.hk-typeset .vc_col-sm-6 p,
.hk-typeset .vc_col-sm-7 p { font-size: 1.125rem; line-height: 1.62; }

/* The two-thirds and three-quarter columns were the gap in the set above, and
   it only shows on a wide monitor. /for-business/bulk-whitelabel/white-label-process/
   builds its six process steps as vc_col-sm-3 (a step number and a timeline
   caption) beside vc_col-sm-9 (the whole explanation). Every other partial
   column here steps the type down; 8 and 9 did not, so they held the blog's
   24px while sitting next to a column that is nearly empty.

   Measured at 2380px, which is the width the operator actually uses: the text
   block runs 997px between a 738px left gutter and a 645px right one, with a
   108px dead gap inside it. At 1440px none of this is visible, which is why
   two passes over this page missed it — the defect only exists above the
   1200px breakpoint the rule above already handles below.

   The measure stays; only the size eases, same as every rule above. */
   SPECIFICITY, because the first version of this rule did nothing. Written as
   `.hk-typeset .vc_col-sm-9 p` it is (0,2,1) and loses to
   `.hk-typeset .entry-content .wpb_text_column p` at (0,3,1) forty lines above,
   which sets var(--prose-size). Measured before and after: text block 997px
   wide both times, byte-identical. The selector below carries .entry-content
   so it matches at (0,3,1) and wins on order. Worth noting the same doubt
   applies to the vc_col-sm-3/4/5/6/7 rules above — they are (0,2,1) too, and
   only take effect where the paragraph is NOT inside .entry-content
   .wpb_text_column. */
.hk-typeset .entry-content .vc_col-sm-8 p,
.hk-typeset .entry-content .vc_col-sm-9 p,
.hk-typeset .entry-content .vc_col-sm-8 li,
.hk-typeset .entry-content .vc_col-sm-9 li { font-size: 1.1875rem; line-height: 1.6; }

/* ---------------------------------------------------------------------------
 * THE BREADCRUMB
 *
 * The captured trail sat in a white strip between the black navigation and
 * the dark hero — a bright sliver cutting the header in half, which is what
 * made it read as an accident rather than a component.
 *
 * It is part of the header furniture now: the same black as the bar above it,
 * separated by the same hairline, so navigation → trail → hero is one
 * continuous dark run and the page starts where the content starts.
 * ------------------------------------------------------------------------ */

.hkb {
  background: var(--black);
  border-bottom: 1px solid var(--rule-dark);
  font-family: var(--sans);
}

.hkb__list {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  list-style: none;
  margin: 0 auto;
  padding: 0.75rem 1.5rem;
  max-width: var(--container);
  font-size: var(--t-micro);          /* 11px — the eyebrow size */
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.hkb__item { display: flex; align-items: center; gap: 0.5rem; }

/* The separator is drawn, not typed: no icon font, and it cannot be selected
   or read aloud as punctuation. */
.hkb__item + .hkb__item::before {
  content: "";
  width: 0.32em; height: 0.32em;
  border-top: 1px solid var(--dim-dark);
  border-right: 1px solid var(--dim-dark);
  transform: rotate(45deg);
  opacity: .7;
  flex: none;
}

.hkb__link { color: var(--dim-dark); text-decoration: none; }   /* 10.78:1 */
.hkb__link:hover, .hkb__link:focus-visible { color: var(--accent-light); }

/* The current page is text. The captured markup made it an anchor with
   href="" on all 81 pages, which reloads the page you are already on. */
.hkb__here { color: var(--fg-dark); }                            /* 15.46:1 */

@media (max-width: 1024px) {
  .hkb__list { padding-inline: 1.25rem; }
}

/* ---------------------------------------------------------------------------
 * THE HOMEPAGE HERO
 *
 * Rebuilt to the shape of /reparasi-buku/, which is the operator's own
 * hand-written hero and the pattern the rest of the site already follows —
 * 50 of the 62 written pages use it verbatim. The homepage was the odd one
 * out: generated, centred, 56px Abril Fatface over an unmasked photograph.
 *
 * Measured off reparasi-buku, not chosen:
 *     overlay        rgba(0, 0, 0, .79)      its .jeg_row_overlay
 *     text column    585px                   its left column
 *     padding        120px top / 170px bottom
 *     h1             33px Lato, white, left-aligned
 *
 * The homepage has no .jeg_row_overlay element, so the mask is drawn with a
 * pseudo-element instead of adding markup to generated content.
 * ------------------------------------------------------------------------ */

#hero-section { position: relative; isolation: isolate; }

#hero-section::before {
  content: "";
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, .79);
  pointer-events: none;
  z-index: 0;
}
#hero-section > * { position: relative; z-index: 1; }

/* One column, held to the left half, so the photograph reads on the right —
   the whole point of the reparasi composition. */
#hero-section .wpb_column { max-width: 585px; margin-inline: 0; }
#hero-section .jeg_wrapper { text-align: left; }

#hero-section .row { padding-top: 120px !important; padding-bottom: 170px !important; }

/* The heading: the theme's own Lato at reparasi's size, not the generated
   56px Abril Fatface. Abril was loaded from Google Fonts for this one
   element on this one page. */
#hero-section h1,
#hero-section .vc_custom_heading,
#hero-section .vc_custom_heading * {
  font-family: var(--sans) !important;
  font-size: 2.0625rem !important;   /* 33px — reparasi's */
  line-height: 1.22 !important;
  font-weight: 700 !important;
  letter-spacing: -0.02em !important;
  color: #FFFFFF !important;
  text-align: left !important;
  max-width: 100%;
}

/* Lead copy: the prose typeset, reversed out. --prose-fg is for light
   grounds and would be unreadable here. */
#hero-section p,
#hero-section .wpb_text_column p {
  color: var(--fg-dark) !important;   /* 15.46:1 on the masked photograph */
  text-align: left !important;
  max-width: 34em;
}

/* Buttons sit on the left and stay square, as everywhere else.
   The secondary button shipped with #666 text on the masked photograph —
   2.42:1, well under AA. Reversed out it is 18.9:1. It is an outline button
   on a dark ground, so the border and label both take the light. */
#hero-section .vc_btn3-container { text-align: left !important; }
#hero-section .vc_btn3 { border-radius: var(--radius) !important; }
#hero-section .vc_btn3:not(.vc_btn3-color-juicy-pink):not([class*="vc_btn3-style-flat"]) {
  color: var(--paper) !important;
  border-color: rgba(255, 255, 255, .55) !important;
}
#hero-section .vc_btn3:hover { border-color: var(--paper) !important; }

@media (max-width: 1024px) {
  #hero-section .wpb_column { max-width: none; }
  #hero-section .row { padding-top: 72px !important; padding-bottom: 88px !important; }
  #hero-section h1, #hero-section .vc_custom_heading * { font-size: 1.75rem !important; }
}

/* ---------------------------------------------------------------------------
 * Emoji, belt and braces.
 *
 * WordPress rewrote every emoji into an <img> from s.w.org and then shipped a
 * stylesheet whose only job was to shrink it back to 1em. The purge removes
 * both — the images are replaced by the characters they stood for — but if a
 * single one ever survives in content we have not regenerated, this stops it
 * rendering at its natural 1140px and swallowing the page. That happened.
 * ------------------------------------------------------------------------ */
img.emoji, img.wp-smiley {
  display: inline !important;
  width: 1em !important;
  height: 1em !important;
  margin: 0 .07em !important;
  vertical-align: -.1em !important;
  border: none !important;
  box-shadow: none !important;
  padding: 0 !important;
  background: none !important;
}

/* ---------------------------------------------------------------------------
 * THE TRUST LAYER
 *
 * Replaces three stacked full-width bands — statistics on brown, credentials
 * on grey, partner logos on white — that were hand-written into the homepage
 * and existed nowhere else. Three grounds in a row is the striping CLAUDE.md
 * warns about; the fix is one ground and hairlines, which is the same move
 * the rest of this design makes.
 *
 * Three tiers, divided by 1px rules:
 *     statistics    the display face, because the numbers are the point
 *     credentials   a real <dl> grid — the original was a flex row with <br>
 *                   tags in it, which is what stranded the "|" separators
 *     partner marks grayscale, other people's brand colours held neutral
 *
 * No accent is spent here. The page already spends its one on the nav CTA,
 * and "once per view" is the rule.
 * ------------------------------------------------------------------------ */

.hkt {
  border-top: 1px solid var(--hairline);
  background: var(--bg);
  font-family: var(--sans);
}

/* The component has to survive being placed INSIDE .entry-content, which is
   where the homepage slot puts it. The theme styles content lists — measured
   on "/": .hkt__stats computed to list-style square with 30px of padding, and
   .hkt__names carried an 18.75px bottom margin, neither of which happened on
   /about/ where the layer sits above the footer instead. Element+class
   compounds put these at (0,2,1), above the theme's (0,1,1) content rules, so
   the layer looks the same wherever it is dropped. */
.hkt ul.hkt__stats,
.hkt ul.hkt__logos,
.hkt dl.hkt__creds { list-style: none; padding-left: 0; margin-left: 0; }

.hkt li.hkt__stat,
.hkt li.hkt__logoitem { list-style: none; margin: 0; padding: 0; }

.hkt dt.hkt__term,
.hkt dd.hkt__names { margin: 0; padding: 0; }

.hkt__inner {
  max-width: var(--container);
  margin-inline: auto;
  padding: 3.5rem 1.5rem 3rem;
}

.hkt__eyebrow {
  margin: 0 0 2.25rem;
  font-family: var(--sans);
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-muted);          /* 4.87:1 on white */
  text-align: center;
}

/* — tier 1: the numbers — */
.hkt__stats {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 2rem 1rem;
  list-style: none;
  margin: 0;
  padding: 0 0 2.75rem;
}

.hkt__stat { text-align: center; }

.hkt__num {
  display: block;
  font-family: var(--display);     /* Palatino — the signature face */
  font-size: 2.125rem;
  line-height: 1.05;
  letter-spacing: -0.015em;
  color: var(--fg-heading);
  font-variant-numeric: lining-nums tabular-nums;
}

.hkt__cap {
  display: block;
  margin-top: 0.6rem;
  font-size: var(--t-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fg-muted);
}

/* — tier 2: who trusts us — */
/* The credentials sat in a two-column grid whose right half ran to the full
   1170px container and was empty past about 600px of it. The rule moves to
   this row so the photograph sits inside the same hairline box, and the list
   keeps its own intrinsic width instead of stretching to fill nothing. */
.hkt__credrow {
  padding: 2.75rem 0;
  border-top: 1px solid var(--hairline);
}
.hkt__credrow--photo {
  display: grid;
  /* 0.62, not 0.82: at the wider setting the 16:9 frame stood about twice the
     height of the four credential rows beside it and the row read lopsided. */
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.62fr);
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: center;
}

.hkt__photo { margin: 0; }
.hkt__photo img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}
.hkt__photo figcaption {
  margin-top: 0.625rem;
  font-family: var(--sans);
  font-size: var(--t-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-muted);
}

@media (max-width: 767px) {
  .hkt__credrow--photo { grid-template-columns: 1fr; }
  /* Photo under the list on a phone: the credentials are the substance and
     they should not be pushed below the fold by a group shot. */
  .hkt__photo { order: 2; }
}

.hkt__creds {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.85rem 2rem;
  margin: 0;
  font-size: 0.9375rem;
}

.hkt__term {
  margin: 0;
  font-size: var(--t-micro);
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-muted);
  line-height: 1.75;               /* optical baseline match with the names */
}

.hkt__names { margin: 0; color: var(--fg); line-height: 1.75; }

/* — tier 3: the marks — */
.hkt__logos {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 2rem 4rem;
  list-style: none;
  margin: 0;
  padding: 2.75rem 0 0;
  border-top: 1px solid var(--hairline);
}

.hkt__logoitem { display: flex; }

/* Height is fixed and width follows, so three marks with different intrinsic
   sizes (120x80, 100x80, 160x80) sit on one optical line.
   56px, not 40: the source files are only 80px tall, and at 40 the two smaller
   marks rendered ~50px wide and their wordmarks were unreadable. 56 is 70% of
   intrinsic, so they are still sharp. Opacity .7 rather than .55 for the same
   reason — held back from the text, but legible. */
.hkt__logo {
  display: block;
  height: 56px;
  width: auto;
  filter: grayscale(1);
  opacity: 0.7;
  transition: opacity .15s ease, filter .15s ease;
}

.hkt__logolink:hover .hkt__logo,
.hkt__logolink:focus-visible .hkt__logo { filter: grayscale(0); opacity: 1; }

/* — tier 4: the document — */
/* The three tiers above are assertions. This is the one a reader can take away
   and check, so it closes the band on its own hairline rather than sitting
   inside another tier.

   It is the only control in the layer, and it is set as one: the measured
   button spec — square, uppercase, 13px, 1px of tracking — not as a link.

   NO ACCENT. The rule is one tan element per view and the header CTA already
   spends it; a second here would put two competing calls to action on the same
   screen. The weight comes from the hairline box and the ink inversion instead,
   which is the same vocabulary the rest of the band uses.

   Every selector below is an element+class compound for the reason given at the
   top of this component: the band renders INSIDE .entry-content on the
   homepage, where the theme styles `a` and `p` at (0,1,1) and would otherwise
   outrank a bare class at (0,1,0) — taking the link colour and adding a
   paragraph margin that exists nowhere else the layer is used. */
.hkt__dl {
  padding: 2.75rem 0 0;
  border-top: 1px solid var(--hairline);
  text-align: center;
}

.hkt a.hkt__dlbtn {
  display: inline-flex;
  align-items: center;
  gap: 0.875rem;
  padding: 1rem 1.75rem;
  border: 1px solid var(--fg-heading);
  border-radius: 0;                /* the measured button spec */
  color: var(--fg-heading);
  text-align: left;
  text-decoration: none;
  transition: background-color .15s ease, color .15s ease;
}

.hkt a.hkt__dlbtn:hover,
.hkt a.hkt__dlbtn:focus-visible {
  background: var(--fg-heading);
  color: var(--bg);
  text-decoration: none;
}

.hkt__dlicon { flex: none; }

.hkt__dllabel {
  display: block;
  font-size: 0.8125rem;            /* 13px */
  font-weight: 700;
  letter-spacing: 0.077em;         /* 1px at 13px */
  text-transform: uppercase;
}

.hkt__dlmeta {
  display: block;
  margin-top: 0.3rem;
  font-size: var(--t-micro);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fg-muted);
  font-variant-numeric: lining-nums tabular-nums;
}

/* The meta line has to follow the inversion. Left at --fg-muted it stays grey
   on the ink ground, where it measures 2.4:1 and is unreadable — the state that
   is hardest to notice, because it only exists under the pointer. */
.hkt a.hkt__dlbtn:hover .hkt__dlmeta,
.hkt a.hkt__dlbtn:focus-visible .hkt__dlmeta { color: inherit; }

.hkt p.hkt__dlnote {
  margin: 1rem 0 0;
  font-size: var(--t-micro);
  letter-spacing: 0.04em;
  color: var(--fg-muted);
}

@media (max-width: 900px) {
  /* 1.5rem to stay on the page's single left edge — see .hkh */
  .hkt__inner { padding: 2.5rem 1.5rem 2.25rem; }
  .hkt__stats { grid-template-columns: repeat(2, 1fr); }
  .hkt__num { font-size: 1.75rem; }
  .hkt__creds { grid-template-columns: 1fr; gap: 0.25rem; }
  .hkt__term { margin-top: 1rem; }
  .hkt__logos { gap: 1.5rem 2.5rem; }
  .hkt__dl { padding-top: 2rem; }
}

/* The label is 31 uppercase characters with 1px of tracking. Measured, it wants
   about 383px of button; a 390px phone offers 342 inside the layer's own
   padding, so as an inline-flex box it overflows the viewport. Full width lets
   the text wrap instead, which costs one line and no horizontal scroll. */
@media (max-width: 560px) {
  .hkt a.hkt__dlbtn {
    display: flex;
    width: 100%;
    padding: 0.9rem 1.1rem;
  }
  .hkt__dllabel { letter-spacing: 0.05em; }
}

/* One column below 380px: two stat columns put "2.000 pcs" on two lines. */
@media (max-width: 380px) {
  .hkt__stats { grid-template-columns: 1fr; }
}

/* ── /press/ ────────────────────────────────────────────────────────────────
   A press page is a list of claims someone else can check, so it is set as a
   record rather than as marketing: hairline rules, no cards, no logo wall.
   Entries that were opened and returned 200 are links; entries that exist
   only in the owner's archive are plain text under a heading that says so,
   and the two are visually distinct without one being dressed as the other. */
.hk-press { max-width: 46rem; }

.hk-press-lede {
  font-family: var(--sans);
  font-size: 1.0625rem;
  line-height: 1.65;
  color: var(--fg);
  margin: 0 0 2.5rem;
}

.hk-press-h {
  font-family: var(--display);
  font-size: 1.375rem;
  font-weight: 400;
  letter-spacing: 0.01em;
  color: var(--fg);
  margin: 2.75rem 0 0;
  padding-bottom: 0.625rem;
  border-bottom: 1px solid var(--hairline);
}

.hk-press-list { list-style: none; margin: 0; padding: 0; }

.hk-press-item {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  padding: 0.875rem 0;
  border-bottom: 1px solid var(--hairline);
}

.hk-press-link {
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.45;
  color: var(--fg);
  text-decoration: none;
  border-bottom: 1px solid var(--accent);
  align-self: flex-start;
}

.hk-press-link:hover,
.hk-press-link:focus-visible { color: var(--accent); }

/* Unlinked entries carry no underline and no accent — nothing to click, and
   nothing that reads as clickable. */
.hk-press-title {
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.45;
  color: var(--fg);
}

.hk-press-meta {
  font-family: var(--sans);
  font-size: 0.8125rem;
  letter-spacing: 0.02em;
  color: var(--fg-muted);
}

.hk-press-note {
  font-family: var(--sans);
  font-size: 0.875rem;
  line-height: 1.55;
  color: var(--fg-muted);
  margin: 1.25rem 0 0.5rem;
}

/* ── the homepage ───────────────────────────────────────────────────────────
   Rebuilt from scratch: the captured body carried 231 inline style attributes
   and fourteen sections. Everything below is token-driven, and there is not
   one style attribute in the markup it styles.

   Sections are divided by hairlines and by space, never by alternating
   background colour — nine stacked coloured bands read as stripes, which is
   what the first attempt did. The two dark passages here are PHOTOGRAPHS with
   a veil over them, not painted blocks.

   Every button is square. border-radius is 0 and stays 0. */

/* THE CONTAINER. On the homepage the theme's .jeg_container does not
   constrain anything — measured at 1440px wide with zero inset — so every
   section that trusted it ran flush to the viewport while the hero, the trust
   band and the repair band sat correctly at 135px. That ragged left edge was
   the messy margin. The page now owns its own measure and does not ask the
   theme for one. */
.hkh {
  --hkh-gap: clamp(3.5rem, 7vw, 7rem);
  max-width: var(--container, 1170px);
  margin-inline: auto;
  /* 1.5rem, not 1.25 — this must equal the footer's .hkf__inner padding or the
     page and the footer sit on two different left edges, 4px apart. */
  padding-inline: 1.5rem;
}

/* The trust band is a full-width band, so it breaks out of .hkh like the hero
   and the repair band do. Left nested it inherited .hkh's inset AND applied
   its own 24px on top, putting its content 24px right of everything else.

   SCOPED TO .hkh ON 2026-08-09, and the scoping is the whole point. The rule
   was written for the homepage and shipped as a bare #id, so it applied to
   every template that renders the slot. body.php fills the slot on 314 routes
   and 212 of them put it inside .jeg_column.col-sm-8 — a ~770px column with a
   sidebar beside it. There, margin-left: calc(50% - 50vw) resolves against the
   COLUMN (50% of 770 = 385px) and subtracts half the VIEWPORT (640px at
   1280px), so the band jumped 255px to the left, ran under the sidebar, and
   clipped its own first statistic off the screen edge.

   Same shape as the .hkb collision recorded in CLAUDE.md: a full-bleed recipe
   written for one context, applied everywhere by a selector that did not say
   where it belonged. Every gate stayed green for this one too — no markup
   changed, nothing 404s, contrast was untouched. It took a screenshot of a
   product page. MEASURE LAYOUT, LOOK AT PAINT. */
.hkh #hk-trust-slot {
  width: 100vw;
  margin-left: calc(50% - 50vw);
}

/* Full-bleed out of the theme's fixed-width container. The page must never
   scroll sideways as a result — verified at 1440/1024/768/390. */
.hkh-hero,
.hkh-band {
  position: relative;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  overflow: hidden;
  isolation: isolate;
}

.hkh-hero { min-height: min(82vh, 720px); display: flex; align-items: flex-end; }

.hkh-hero__img,
.hkh-band__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: -2;
}

/* Bottom-weighted so the type sits on the darkest part of the frame instead
   of on the subject. */
.hkh-hero__veil,
.hkh-band__veil {
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(
    to top, rgba(16,16,24,0.88) 0%, rgba(16,16,24,0.62) 38%,
    rgba(16,16,24,0.22) 70%, rgba(16,16,24,0.10) 100%);
}

.hkh-hero__inner,
.hkh-band__inner {
  width: 100%;
  max-width: var(--container, 1170px);
  margin: 0 auto;
  padding: clamp(2.5rem, 6vw, 5.5rem) 1.5rem clamp(2.75rem, 5vw, 4.5rem);
}

.hkh-eyebrow {
  font-family: var(--sans);
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 1rem;
}

.hkh-hero__inner .hkh-eyebrow,
.hkh-band__inner .hkh-eyebrow { color: #D8A87F; }

/* A veil is tuned to a crop, and the crop changes with the viewport.
 *
 * The gradient above is bottom-weighted (0.88 at the foot, 0.10 at the head)
 * and it is right for the desktop 21:9 band: at min(62vh, 540px) the text sits
 * low, over the dark left third of the photograph, and the eyebrow measures
 * 7.60:1. On a 390px phone the same section is far taller because the copy
 * wraps, so the text climbs into the 0.10-0.22 zone — and the mobile crop
 * centres the brightest thing in the frame, the open cream book page, directly
 * behind it. Measured there: the eyebrow fell to 1.32:1, against a 4.5 floor.
 *
 * It is invisible on a desktop screenshot, which is exactly why it shipped, and
 * 71% of this site's clicks are phones. The lesson is already in CLAUDE.md from
 * /hibrkraft-experience/ — a shared veil is not portable — this is the same
 * class on the homepage.
 *
 * The floor is raised rather than the whole gradient flattened, so the
 * photograph is still legibly a photograph. Verified by measurement, not by
 * eye: see the ratios recorded at the breakpoint below. */
@media (max-width: 1023px) {
  .hkh-band__veil {
    background: linear-gradient(
      to top, rgba(16,16,24,0.92) 0%, rgba(16,16,24,0.86) 40%,
      rgba(16,16,24,0.80) 72%, rgba(16,16,24,0.76) 100%);
  }
}

.hkh-hero__title {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(2.25rem, 5.4vw, 4.25rem);
  line-height: 1.04;
  letter-spacing: -0.015em;
  color: #FFFFFF;
  margin: 0 0 1.25rem;
  max-width: 18ch;
}

.hkh-hero__lede {
  font-family: var(--sans);
  font-size: clamp(1rem, 1.35vw, 1.1875rem);
  line-height: 1.6;
  color: rgba(255,255,255,0.88);
  margin: 0 0 2rem;
  max-width: 46ch;
}

/* ── buttons: square, uppercase, 13px, 1px tracking (the measured spec) ──── */
.hkh-btn {
  display: inline-block;
  border-radius: 0;
  font-family: var(--sans);
  font-size: 0.8125rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 0.95rem 1.9rem;
  text-decoration: none;
  border: 1px solid transparent;
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}

.hkh-btn + .hkh-btn { margin-left: 0.75rem; }

.hkh-btn--solid { background: var(--accent); color: #FFFFFF; border-color: var(--accent); }
.hkh-btn--solid:hover,
.hkh-btn--solid:focus-visible { background: var(--accent-deep, #6F4630); border-color: var(--accent-deep, #6F4630); color: #FFFFFF; }

.hkh-btn--ghost { color: #FFFFFF; border-color: rgba(255,255,255,0.55); }
.hkh-btn--ghost:hover,
.hkh-btn--ghost:focus-visible { background: #FFFFFF; color: #101018; border-color: #FFFFFF; }

.hkh-btn--light { background: #FFFFFF; color: #101018; border-color: #FFFFFF; }
.hkh-btn--light:hover,
.hkh-btn--light:focus-visible { background: transparent; color: #FFFFFF; border-color: #FFFFFF; }

.hkh-arrow {
  font-family: var(--sans);
  font-size: 0.875rem;
  letter-spacing: 0.02em;
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  padding-bottom: 2px;
}
.hkh-arrow::after { content: " →"; }
.hkh-arrow:hover, .hkh-arrow:focus-visible { color: var(--fg); }

.hkh-h2 {
  font-family: var(--display);
  font-weight: 400;
  font-size: clamp(1.625rem, 2.9vw, 2.375rem);
  line-height: 1.15;
  letter-spacing: -0.01em;
  color: var(--fg-heading, var(--fg));
  margin: 0 0 1.125rem;
  max-width: 24ch;
  /* Without this "Kenapa dijahit, bukan dilem" breaks with "dilem" alone on
     line two. Ignored by browsers that do not support it, which is fine. */
  text-wrap: balance;
}
.hkh-h2--light { color: #FFFFFF; }

/* The jNews back-to-top control ships at border-radius 5px — the one round
   corner left on the page, and stock Material Design in a design that is
   square everywhere else. It is theme CSS, so it is corrected here rather
   than edited under wp-content/, which the build overwrites wholesale. */
.jscroll-to-top_link,
.jscroll-to-top { border-radius: 0 !important; }

/* Content tables, 2026-08-09. The 21 /for-business/ pages each carried their
   own table styling as inline attributes — border: 1px solid #ccc, padding:
   10px, a header fill — which was 21 near-identical copies inlined into 21
   responses. Removing them and trusting the theme was the obvious move and it
   was wrong: jNews gives content tables only
   `body:not(.jnews-disable-style-table) .entry-content tr{border-bottom:1px
   solid #eee}` — a faint row rule, no cell padding, no header weight. A
   comparison table rendered as unseparated text. Caught by looking at the
   page, not by reading the CSS.

   One shared rule instead. It is cached with the stylesheet rather than
   inlined per page, which is the faster arrangement AND the consistent one.
   Styling follows .hkj__tbl so a table looks the same wherever it appears.

   !important for the reason given at the top of this file: the theme selector
   above is (0,2,2) and a bare class is (0,1,0). Same trap that cost .hk-p12
   and .hk-bd 56 cells each. */
.entry-content table:not(.hkj__tbl):not(.variations):not(.shop_attributes) {
  border-collapse: collapse !important;
  width: 100% !important;
  font-family: var(--sans) !important;
  font-size: 14px !important;
  line-height: 1.5 !important;
  margin: 18px 0 0 !important;
}
.entry-content table:not(.hkj__tbl):not(.variations):not(.shop_attributes) th {
  text-align: left !important;
  font-weight: 400 !important;
  font-size: 11px !important;
  letter-spacing: .1em !important;
  text-transform: uppercase !important;
  color: var(--fg-muted) !important;
  background: none !important;
  border-bottom: 1px solid var(--fg) !important;
  padding: 0 14px 7px 0 !important;
}
.entry-content table:not(.hkj__tbl):not(.variations):not(.shop_attributes) td {
  padding: 9px 14px 9px 0 !important;
  border: 0 !important;
  border-bottom: 1px solid var(--hairline) !important;
  vertical-align: top !important;
}

/* WPBakery button shapes, squared 2026-08-09. The same defect as the control
   above and it survived because the fix for it was scoped: site.css squared
   `#hero-section .vc_btn3` only, so every button OUTSIDE the hero kept the
   theme's own `.vc_btn3-shape-rounded{border-radius:5px}` — including the
   WhatsApp CTA at the foot of all 21 /for-business/ pages. 31 buttons across
   the tree: 26 rounded, 5 fully round.

   Found by looking, not by reading CSS. --radius is already 0 in tokens.css,
   the measured button spec says square, and site.css says in a comment three
   hundred lines above that "Every button is square. border-radius is 0 and
   stays 0" — all three were true and all three were beside the point, because
   the selector that enforced them did not reach these elements. */
.vc_btn3,
.vc_btn3.vc_btn3-shape-rounded,
.vc_btn3.vc_btn3-shape-round { border-radius: var(--radius) !important; }

/* ── the three doors ─────────────────────────────────────────────────────── */
.hkh-doors {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.5rem, 2.5vw, 2.5rem);
  padding: var(--hkh-gap) 0;
  border-bottom: 1px solid var(--hairline);
}

/* Hibrkraft World has four doors, not three — glosarium, jurnal, template and
 * experience. Declared HERE, beside the base, and deliberately not further
 * down the file: the collapse to one column lives in an
 * @media (max-width: 900px) block near the foot, and a modifier placed after
 * that block would out-order it and ship two cramped columns on a phone. Here
 * the existing collapse still governs both variants, which is what we want.
 * At >900px each tile is ~270px in the 1170px container. */
.hkh-doors--4 { grid-template-columns: repeat(4, 1fr); }

/* A heading that spans the whole grid. It sits INSIDE .hkh-doors rather than
 * in a section above it, because .hkx-who — the block this replaced — carries
 * its own padding and bottom hairline, and using it here drew a rule between
 * the heading and the tiles it introduces. */
.hkh-doors__head { grid-column: 1 / -1; margin-bottom: 0.25rem; }

/* No internal rules and no horizontal padding: a border between the tiles put
   a hairline hard against the photographs, and the padding pushed the first
   tile's image 28px inside the container while every other section started at
   the edge. */
.hkh-door { display: block; text-decoration: none; }

.hkh-door__frame {
  display: block;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--paper, #F4F2EF);
  margin-bottom: 1.5rem;
}

.hkh-door__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform .5s cubic-bezier(.2,.7,.3,1);
}
.hkh-door:hover .hkh-door__img,
.hkh-door:focus-visible .hkh-door__img { transform: scale(1.035); }

.hkh-door__body { display: block; }

.hkh-door__label {
  display: block;
  font-family: var(--display);
  font-size: 1.375rem;
  color: var(--fg-heading, var(--fg));
  margin-bottom: 0.5rem;
}

.hkh-door__blurb {
  display: block;
  font-family: var(--sans);
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--fg-muted);
  margin-bottom: 1rem;
}

.hkh-door__more {
  font-family: var(--sans);
  font-size: 0.8125rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
}
.hkh-door__more::after { content: " →"; }

/* ── image + text ────────────────────────────────────────────────────────── */
.hkh-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: center;
  padding: var(--hkh-gap) 0;
  border-bottom: 1px solid var(--hairline);
}
.hkh-split--flip .hkh-split__media { order: 2; }

.hkh-split__media { aspect-ratio: 1 / 1; overflow: hidden; background: var(--paper, #F4F2EF); }
.hkh-split__img { width: 100%; height: 100%; object-fit: cover; display: block; }

.hkh-split__text p {
  font-family: var(--sans);
  font-size: 1.0625rem;
  line-height: 1.7;
  color: var(--fg);
  max-width: 46ch;
  margin: 0 0 1rem;
}
.hkh-split__cta { margin-top: 1.5rem; }

/* ── the repair band ─────────────────────────────────────────────────────── */
.hkh-band { min-height: min(62vh, 540px); display: flex; align-items: center; margin-top: 0; }
.hkh-band__lede {
  font-family: var(--sans);
  font-size: clamp(1rem, 1.3vw, 1.125rem);
  line-height: 1.65;
  color: rgba(255,255,255,0.9);
  max-width: 52ch;
  margin: 0 0 2rem;
}

/* ── journal ─────────────────────────────────────────────────────────────── */
.hkh-journal { padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline); }

.hkh-journal__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.5rem;
  margin-bottom: 2.5rem;
}
.hkh-journal__head .hkh-h2 { margin-bottom: 0; }

.hkh-journal__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 2rem; }

.hkh-post { display: block; text-decoration: none; }
.hkh-post__frame {
  display: block;
  aspect-ratio: 3 / 2;
  overflow: hidden;
  background: var(--paper, #F4F2EF);
  margin-bottom: 1rem;
}
.hkh-post__img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .5s cubic-bezier(.2,.7,.3,1);
}
.hkh-post:hover .hkh-post__img { transform: scale(1.035); }

.hkh-post__title {
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.5;
  color: var(--fg);
  display: block;
}
.hkh-post:hover .hkh-post__title { color: var(--accent); }

/* ── Cara Pesan ─────────────────────────────────────────────────────────── */
.hkh-steps { padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline); }
.hkh-steps__list {
  list-style: none; margin: 2.25rem 0 0; padding: 0;
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.5rem, 3vw, 3rem);
}
.hkh-step { display: block; }
.hkh-step__frame {
  display: block; aspect-ratio: 3 / 2; overflow: hidden;
  background: var(--paper, #F4F2EF); margin-bottom: 1.25rem;
}
.hkh-step__img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hkh-step__n {
  border-top: 2px solid var(--accent); padding-top: 0.875rem;
}
.hkh-step__n {
  display: block; font-family: var(--sans); font-size: 0.75rem;
  letter-spacing: 0.16em; color: var(--accent); margin-bottom: 0.75rem;
}
.hkh-step__t {
  display: block; font-family: var(--display); font-size: 1.25rem;
  color: var(--fg-heading, var(--fg)); margin-bottom: 0.5rem;
}
.hkh-step__b {
  display: block; font-family: var(--sans); font-size: 0.9375rem;
  line-height: 1.65; color: var(--fg-muted);
}

/* ── katalog ────────────────────────────────────────────────────────────── */
.hkh-cat { padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline); }
.hkh-cat__head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 1.5rem; margin-bottom: 2rem; flex-wrap: wrap;
}
.hkh-cat__head .hkh-h2 { margin-bottom: 0; }
.hkh-cat__meta {
  font-family: var(--sans); font-size: 0.9375rem; line-height: 1.9;
  color: var(--fg-muted); margin: 0; text-align: right;
}
.hkh-cat__grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.25rem; }
.hkh-cat__frame {
  display: block; aspect-ratio: 1 / 1; overflow: hidden;
  background: var(--paper, #F4F2EF);
}
.hkh-cat__img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .5s cubic-bezier(.2,.7,.3,1);
}
.hkh-cat__item:hover .hkh-cat__img { transform: scale(1.04); }

/* ── corporate gifting ──────────────────────────────────────────────────── */
.hkh-gift {
  padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline);
  display: grid; grid-template-columns: 0.85fr 1fr;
  gap: clamp(2rem, 5vw, 4.5rem); align-items: center;
}
.hkh-gift__media { aspect-ratio: 4 / 5; overflow: hidden; background: var(--paper, #F4F2EF); }
.hkh-gift__img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hkh-gift__head { margin-bottom: 1.75rem; }
.hkh-gift__list { list-style: none; margin: 0; padding: 0; }
.hkh-gift__item { border-top: 1px solid var(--hairline); }
.hkh-gift__item:last-child { border-bottom: 1px solid var(--hairline); }
.hkh-gift__item a {
  display: flex; align-items: baseline; gap: 1.5rem;
  padding: 1.125rem 0; text-decoration: none;
  transition: padding-left .2s ease;
}
.hkh-gift__item a:hover, .hkh-gift__item a:focus-visible { padding-left: 0.75rem; }
.hkh-gift__label {
  font-family: var(--display); font-size: 1.1875rem;
  color: var(--fg-heading, var(--fg)); flex: 0 0 15rem;
}
.hkh-gift__blurb {
  font-family: var(--sans); font-size: 0.9375rem; color: var(--fg-muted);
}
.hkh-gift__item a:hover .hkh-gift__label { color: var(--accent); }

/* ── glosarium ──────────────────────────────────────────────────────────── */
.hkh-gloss { padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline); }
.hkh-gloss__head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 1.5rem; margin-bottom: 2rem; flex-wrap: wrap;
}
.hkh-gloss__head .hkh-h2 { margin-bottom: 0; }
.hkh-gloss__list {
  margin: 0; display: grid; grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.5rem, 3vw, 2.5rem);
}
.hkh-gloss__row { padding: 0; }
.hkh-gloss__t { margin: 0 0 0.5rem; font-family: var(--display); font-size: 1.0625rem; }
.hkh-gloss__t a { color: var(--fg-heading, var(--fg)); text-decoration: none; display: block; }
.hkh-gloss__frame {
  display: block; aspect-ratio: 3 / 2; overflow: hidden;
  background: var(--paper, #F4F2EF); margin-bottom: 0.875rem;
}
.hkh-gloss__img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .5s cubic-bezier(.2,.7,.3,1);
}
.hkh-gloss__t a:hover .hkh-gloss__img { transform: scale(1.04); }
.hkh-gloss__term { border-bottom: 1px solid var(--accent); }
.hkh-gloss__t a:hover .hkh-gloss__term { color: var(--accent); }
.hkh-gloss__d {
  margin: 0; font-family: var(--sans); font-size: 0.875rem;
  line-height: 1.6; color: var(--fg-muted);
}

/* ── FAQ ────────────────────────────────────────────────────────────────── */
.hkh-faq { padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline); }
.hkh-faq__list {
  margin: 2rem 0 0; display: grid; grid-template-columns: repeat(2, 1fr);
  gap: 0 clamp(2rem, 4vw, 4rem);
}
.hkh-faq__row { padding: 1.25rem 0; border-top: 1px solid var(--hairline); }
.hkh-faq__q {
  margin: 0 0 0.5rem; font-family: var(--sans); font-weight: 700;
  font-size: 0.9375rem; color: var(--fg);
}
.hkh-faq__a {
  margin: 0; font-family: var(--sans); font-size: 0.9375rem;
  line-height: 1.65; color: var(--fg-muted);
}

/* ── diliput oleh ───────────────────────────────────────────────────────── */
.hkh-press { padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline); text-align: center; }
.hkh-press__names {
  font-family: var(--display); font-size: clamp(1rem, 1.6vw, 1.25rem);
  line-height: 1.9; color: var(--fg); max-width: 52rem;
  margin: 0 auto 1.25rem;
}

@media (max-width: 900px) {
  .hkh-steps__list { grid-template-columns: 1fr; }
  .hkh-cat__grid { grid-template-columns: repeat(2, 1fr); }
  .hkh-cat__head, .hkh-gloss__head { flex-direction: column; align-items: flex-start; }
  .hkh-cat__meta { text-align: left; }
  .hkh-gloss__list { grid-template-columns: repeat(2, 1fr); }
  .hkh-faq__list { grid-template-columns: 1fr; }
  .hkh-gift { grid-template-columns: 1fr; }
  .hkh-gift__media { aspect-ratio: 16 / 9; }
  .hkh-gift__item a { flex-direction: column; gap: 0.25rem; }
  .hkh-gift__label { flex: none; }
}

/* ── page-spec framework: grid widths and prose blocks ──────────────────── */
.hkg-2 { grid-template-columns: repeat(2, 1fr) !important; }
.hkg-3 { grid-template-columns: repeat(3, 1fr) !important; }
.hkg-4 { grid-template-columns: repeat(4, 1fr) !important; }

.hkp { padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline); }
.hkp__body p {
  font-family: var(--sans); font-size: 1.0625rem; line-height: 1.7;
  color: var(--fg); max-width: 46ch; margin: 0 0 1rem;
}
.hkp-list { list-style: none; margin: 1.25rem 0 0; padding: 0; max-width: 52ch; }
.hkp-list li {
  position: relative; padding: 0.55rem 0 0.55rem 1.5rem;
  border-top: 1px solid var(--hairline);
  font-family: var(--sans); font-size: 0.9375rem; line-height: 1.6;
  color: var(--fg);
}
.hkp-list li::before { content: "—"; position: absolute; left: 0; color: var(--accent); }

/* A page with no usable photograph for its hero still needs a readable one.
   Rather than a veil over nothing, it gets the ink ground. */
.hkh-hero--flat { background: var(--ink, #101018); min-height: auto; }
.hkh-hero--flat .hkh-hero__veil { display: none; }

@media (max-width: 900px) {
  .hkg-3, .hkg-4 { grid-template-columns: repeat(2, 1fr) !important; }
}
@media (max-width: 560px) {
  .hkg-2, .hkg-3, .hkg-4 { grid-template-columns: 1fr !important; }
}

/* ── the warranty block, printed from config.php ────────────────────────── */
.hkw { margin: 2rem 0 0; }
.hkw__grid { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(1.5rem, 4vw, 3.5rem); }
.hkw__t {
  font-family: var(--sans); font-size: 0.75rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--fg-muted); margin: 0 0 0.75rem;
}
.hkw__t--wide { margin-top: 2.5rem; }
.hkw__list { list-style: none; margin: 0; padding: 0; }
.hkw__list li {
  position: relative; padding: 0.6rem 0 0.6rem 1.5rem;
  border-top: 1px solid var(--hairline);
  font-family: var(--sans); font-size: 0.9375rem; line-height: 1.55; color: var(--fg);
}
.hkw__list li::before { content: "—"; position: absolute; left: 0; color: var(--accent); }
.hkw__list--no li::before { content: "×"; color: var(--fg-muted); }
.hkw__steps { list-style: none; margin: 0; padding: 0; display: grid;
  grid-template-columns: repeat(4, 1fr); gap: 1.25rem; }
.hkw__steps li {
  border-top: 2px solid var(--accent); padding-top: 0.875rem;
  font-family: var(--sans); font-size: 0.9375rem; line-height: 1.5; color: var(--fg);
}
.hkw__steps li span {
  display: block; font-size: 0.75rem; letter-spacing: 0.14em;
  color: var(--accent); margin-bottom: 0.5rem;
}
.hkw__cost {
  font-family: var(--sans); font-size: 0.9375rem; line-height: 1.65;
  color: var(--fg-muted); margin: 2rem 0 0; max-width: 60ch;
  padding-top: 1rem; border-top: 1px solid var(--hairline);
}
@media (max-width: 900px) {
  .hkw__grid { grid-template-columns: 1fr; }
  .hkw__steps { grid-template-columns: repeat(2, 1fr); }
}

/* ── customer reviews, transcribed from the storefront ──────────────────── */
.hkr-wrap { padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline); }
.hkr-head { margin-bottom: 2.25rem; }
.hkr-note {
  font-family: var(--sans); font-size: 0.9375rem; line-height: 1.6;
  color: var(--fg-muted); max-width: 56ch; margin: 0.75rem 0 0;
}
.hkr-grid {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.25rem, 2.5vw, 2rem);
}
.hkr {
  margin: 0; padding: 1.5rem; border: 1px solid var(--hairline);
  display: flex; flex-direction: column; gap: 0.75rem;
}
/* Stars are text, not images: they scale with the type, they survive with CSS
   off, and they cost no request. The unearned ones print hollow. */
.hkr__stars { margin: 0; font-size: 0.875rem; letter-spacing: 0.12em; color: var(--accent); }
.hkr__dim { color: var(--hairline); }
.hkr__q {
  margin: 0; font-family: var(--sans); font-size: 0.9375rem; line-height: 1.6;
  color: var(--fg); flex: 1 1 auto;
}
.hkr__who {
  font-family: var(--sans); font-size: 0.8125rem; color: var(--fg);
  padding-top: 0.75rem; border-top: 1px solid var(--hairline);
}
.hkr__prod {
  display: block; font-size: 0.75rem; line-height: 1.4;
  color: var(--fg-muted); margin-top: 0.2rem;
}
@media (max-width: 900px) { .hkr-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .hkr-grid { grid-template-columns: 1fr; } }

/* ── YouTube facade ─────────────────────────────────────────────────────────
   Poster served from our own uploads; the iframe is created on click. Until
   then this is an ordinary link to youtube.com, which is also exactly what a
   visitor with JavaScript off gets — a working link, not a dead rectangle. */
.hky-wrap { padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline); }
.hky-grid { list-style: none; margin: 2rem 0 0; padding: 0; display: grid;
  gap: clamp(1rem, 2vw, 1.75rem); }
.hky-grid--wide  { grid-template-columns: repeat(2, 1fr); }
.hky-grid--short { grid-template-columns: repeat(5, 1fr); margin-top: 1.75rem; }
/* 4:5, not 9:16. The ten-part "#shorts" series on /reviews/ carries the tag in
   its YouTube title but was shot 4:5, and every poster crop is DETECTED from
   the thumbnail's own black padding rather than assumed — forcing them into
   the 9/16 frame above would cover-crop 30% off both sides of all ten. Five
   columns, because the series is exactly ten and lands as two clean rows. */
.hky-grid--tall  { grid-template-columns: repeat(5, 1fr); margin-top: 1.75rem; }
/* Mixed ratios: 16:9 compilations, one true 9:16 short and a 1:1 montage in
   the same group. A grid row is as tall as its tallest cell, so the 9:16 card
   opened ~500px of white space beside every 16:9 one next to it. Column
   packing instead — same mechanism as the wall below — so each card keeps its
   own aspect and the holes close. Not a grid, so the shared .hky-grid display
   has to be overridden. */
.hky-grid--mix {
  display: block; columns: 3; column-gap: clamp(1rem, 2vw, 1.75rem);
  margin-top: 1.75rem;
}
.hky-grid--mix .hky {
  break-inside: avoid; -webkit-column-break-inside: avoid;
  margin-bottom: clamp(1rem, 2vw, 1.75rem);
}

.hky__link { display: block; text-decoration: none; }
.hky__frame {
  position: relative; display: block; overflow: hidden;
  background: var(--ink, #101018);
}
.hky--wide  .hky__frame { aspect-ratio: 16 / 9; }
.hky--short .hky__frame { aspect-ratio: 9 / 16; }
.hky--tall  .hky__frame { aspect-ratio: 4 / 5; }
.hky--sq    .hky__frame { aspect-ratio: 1 / 1; }
.hky__img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .5s cubic-bezier(.2,.7,.3,1), opacity .2s ease;
}
.hky__link:hover .hky__img { transform: scale(1.03); opacity: .85; }

/* Play button in CSS — no sprite, no icon font, no request. A square, because
   every other control on this site is square. */
.hky__play {
  position: absolute; inset: 0; margin: auto;
  width: 56px; height: 56px; background: rgba(16,16,24,0.72);
  border: 1px solid rgba(255,255,255,0.7);
}
.hky__play::after {
  content: ""; position: absolute; inset: 0; margin: auto;
  width: 0; height: 0;
  border-left: 15px solid #FFFFFF;
  border-top: 10px solid transparent;
  border-bottom: 10px solid transparent;
  transform: translateX(2px);
}
.hky__link:hover .hky__play,
.hky__link:focus-visible .hky__play { background: var(--accent); border-color: var(--accent); }

.hky__body { display: block; padding-top: 0.75rem; }
.hky__t {
  display: block; font-family: var(--sans); font-size: 0.9375rem;
  line-height: 1.45; color: var(--fg);
}
.hky__n {
  display: block; font-family: var(--sans); font-size: 0.8125rem;
  line-height: 1.5; color: var(--fg-muted); margin-top: 0.2rem;
}
/* The swapped-in player inherits the frame's ratio. */
.hky__frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

@media (max-width: 900px) {
  .hky-grid--wide  { grid-template-columns: 1fr; }
  .hky-grid--short { grid-template-columns: repeat(3, 1fr); }
  .hky-grid--tall  { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .hky-grid--short { grid-template-columns: repeat(2, 1fr); }
}

/* ── /reviews/ — what buyers posted themselves ──────────────────────────────
   A multi-column wall, not a fixed-ratio grid, and deliberately so: 82 of
   these files are phone screenshots of an Instagram post or story, where the
   handle, the caption and the like count ARE the evidence. A square tile
   crops off exactly that. Nothing here is cropped — every picture keeps the
   shape its author framed it in, and the columns absorb the ragged mix of
   1:1.94 screenshots, squares and one landscape.

   columns/break-inside rather than grid: a masonry grid would need each
   tile's height declared, which means cropping, which is the thing being
   avoided. Order flows down each column; for an unordered wall that is fine. */

/* The ribbon, and it is the ONE thing that sits above the index.
   Measured before it went in: hero, trust logos, a six-cell text index, then
   thirty-odd text-only quote cards. The first photograph on the page was
   15,029 characters in, so the whole top of a page ABOUT customer photographs
   read as a wall of type.

   Fixed HEIGHT and automatic width — never a square tile with object-fit:
   cover. The wall further down keeps every picture in the shape its author
   framed it in, for the reason given in the comment above, and a ribbon that
   cropped would contradict the page it introduces. The ragged widths are the
   point: they say these came off fourteen different phones.

   The prefix is hks and NOT hkb: .hkb is already the breadcrumb component
   (.hkb__list / .hkb__item / .hkb__link), so the first version of this
   block put width: 100vw and a hairline on every breadcrumb on all 862
   pages. Every gate stayed green — site.css is not in the byte diff and
   no markup changed — and it took counting .hkb elements in the DOM to
   see it. Check a base prefix against the whole tree; never assume one.

   It runs off the right edge deliberately. No viewport fits all fourteen, so
   the cut frame is both the scroll affordance and an honest signal that what
   is on the page is a sample of what exists. */
.hks {
  width: 100vw; margin-left: calc(50% - 50vw);
  padding: var(--hkh-gap) 0;
  border-bottom: 1px solid var(--hairline);
}
.hks__strip {
  list-style: none; margin: 0; display: flex; gap: 2px;
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  /* Same expression as .hkg-bleed's padding, so the first frame lines up with
     the 1170px measure the rest of the page uses and the two cannot drift. */
  padding: 0 1.5rem 0 max(1.5rem, calc(50vw - var(--container, 1170px) / 2));
  /* MUST equal the padding above. Without it, proximity snapping scrolled the
     strip to the first item's snap position on load — measured scrollLeft 135
     at 1440, exactly the padding — and the opening frame sat flush to the
     viewport edge instead of on the measure. The padding was applied correctly
     the whole time; the scroll position ate it. scroll-padding is what tells
     the snapport its start edge is inside the padding. */
  scroll-padding-left: max(1.5rem, calc(50vw - var(--container, 1170px) / 2));
  scrollbar-width: none;
}
.hks__strip::-webkit-scrollbar { display: none; }
/* Keyboard users scroll this with the arrow keys, so it has to show focus. */
.hks__strip:focus-visible { outline: 2px solid var(--accent); outline-offset: -3px; }
.hks__i { flex: 0 0 auto; margin: 0; scroll-snap-align: start; }
.hks__img {
  display: block; height: clamp(180px, 22vw, 310px); width: auto;
  background: var(--paper, #F4F2EF);
}
/* The caption steps back inside the measure. */
.hks__cap {
  margin: 1.125rem 0 0;
  padding: 0 1.5rem 0 max(1.5rem, calc(50vw - var(--container, 1170px) / 2));
  font-family: var(--sans); font-size: 0.8125rem; line-height: 1.55;
  color: var(--fg-muted);
}
.hks__cap a {
  color: var(--fg); text-decoration: none;
  border-bottom: 1px solid var(--hairline); padding-bottom: 2px;
}
.hks__cap a:hover, .hks__cap a:focus-visible { color: var(--accent); }

/* The index. A page this long needs a way in that is not scrolling, and it
   must survive with no JavaScript at all — so it is an ordinary ordered list
   of anchor links, and every count in it is emitted from what the sections
   actually rendered rather than typed by hand. */
.hkx { padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline); }
.hkx__head { margin-bottom: 2rem; }
.hkx__grid {
  list-style: none; margin: 2rem 0 0; padding: 0; display: grid;
  grid-template-columns: repeat(3, 1fr); gap: 1px;
  background: var(--hairline); border: 1px solid var(--hairline);
}
.hkx__i { margin: 0; background: var(--bg, #FFFFFF); }
.hkx__a {
  display: block; padding: 1.5rem 1.375rem; text-decoration: none;
  height: 100%; transition: background 200ms ease;
}
.hkx__a:hover, .hkx__a:focus-visible { background: var(--paper, #F4F2EF); }
.hkx__n {
  display: block; font-family: var(--display); font-size: 1.75rem;
  line-height: 1; color: var(--accent);
}
.hkx__t {
  display: block; font-family: var(--sans); font-size: 0.9375rem;
  color: var(--fg); margin-top: 0.625rem;
}
.hkx__d {
  display: block; font-family: var(--sans); font-size: 0.8125rem;
  line-height: 1.55; color: var(--fg-muted); margin-top: 0.375rem;
}
/* The way back up, at the foot of every long section. */
.hkx-back { margin: 2.5rem 0 0; }
.hkx-back a {
  font-family: var(--sans); font-size: 0.8125rem; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--fg-muted); text-decoration: none;
  border-bottom: 1px solid var(--hairline); padding-bottom: 2px;
}
/* Literal glyph, never a CSS hex escape: SITE_CSS is a plain triple-quoted
   Python string, so "\2191" is read by Python first — the leading digits
   become an octal escape (U+0011) and "91" is left behind as visible text.
   That is the defect that shipped "SELENGKAPNYA 92" on every homepage arrow. */
.hkx-back a::before { content: "↑ "; }
.hkx-back a:hover, .hkx-back a:focus-visible { color: var(--fg); }
/* Anchor targets sit under a sticky header; without this the heading a reader
   just jumped to is hidden behind it. */
[id="daftar-isi"], [id="ulasan-toko"], [id="video"], [id="anyahasna"],
[id="halaman-testimoni"], [id="dinding"], [id="liputan"] { scroll-margin-top: 6rem; }

/* An index of the 61 testimonial pages. These are real pages that until now
   nothing linked to — Search Console measures the whole set at 12 clicks —
   so the cards are the point as much as the pictures. Fixed 4:5 frames here,
   unlike the wall below: this is an INDEX, meant to be scanned, and the
   uncropped picture is one click away on the page itself. */
.hkv-wrap { padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline); }
.hkv-grid {
  list-style: none; margin: 2rem 0 0; padding: 0; display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 1.25rem 0.75rem;
}
.hkv { margin: 0; }
.hkv__link { display: block; text-decoration: none; }
.hkv__frame {
  display: block; aspect-ratio: 4 / 5; overflow: hidden;
  background: var(--paper, #F4F2EF);
}
.hkv__img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .4s cubic-bezier(.2,.7,.3,1), opacity .2s ease;
}
.hkv__link:hover .hkv__img { transform: scale(1.05); opacity: .9; }
.hkv__who {
  display: block; font-family: var(--sans); font-size: 0.8125rem;
  line-height: 1.4; color: var(--fg); margin-top: 0.5rem;
  overflow-wrap: anywhere;
}
.hkv__link:hover .hkv__who { color: var(--accent); }

.hku { padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline); }
.hku__head { margin-bottom: 2rem; }
/* Sub-heading inside a long section. Rule above it, not a background block —
   nine coloured bands read as stripes, which is how the first homepage
   attempt failed. */
.hku__group {
  font-family: var(--sans); font-size: 0.8125rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--fg); font-weight: 600;
  margin: 3rem 0 1rem; padding-top: 1rem; border-top: 1px solid var(--hairline);
}
.hku__group .hku__n {
  font-weight: 400; letter-spacing: 0.04em; text-transform: none;
  color: var(--fg-muted); margin-left: 0.5rem;
}
.hku__wall { columns: 5; column-gap: 0.75rem; margin-top: 2rem; }
.hku__item {
  break-inside: avoid; -webkit-column-break-inside: avoid;
  margin: 0 0 0.75rem; background: var(--paper, #F4F2EF);
}
.hku__img { width: 100%; height: auto; display: block; }

/* One submission told at length. Two pictures rather than one, because they
   are different kinds of evidence: the photograph is the object, the
   screenshot is the receipt — handle, caption and like count intact. */
.hku-story { padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline); }
/* The prose lives INSIDE the left column, under the photograph, rather than
   in a row of its own beneath both. Put it in its own row and the left column
   ends at the shorter figure while the right one runs on, so the page opens a
   150px hole in the middle of the section — which a screenshot shows and no
   markup check can. */
.hku-story__grid {
  display: grid; grid-template-columns: 1.5fr 1fr;
  gap: clamp(1rem, 2vw, 1.75rem); align-items: start; margin-top: 2rem;
}
.hku-story__fig { margin: 0; }
.hku-story__img {
  width: 100%; height: auto; display: block; background: var(--paper, #F4F2EF);
}
.hku-story__cap {
  font-family: var(--sans); font-size: 0.8125rem; line-height: 1.5;
  color: var(--fg-muted); margin-top: 0.75rem;
  padding-top: 0.75rem; border-top: 1px solid var(--hairline);
}
.hku-story__text { margin-top: 2.25rem; max-width: 62ch; }
/* Margin on BOTH sides. With `1.5rem 0 0` the cite line inside the last quote
   sat flush against the paragraph after it — the theme gives <p> no top
   margin, so the blockquote has to own the gap under itself. */
.hku-story__q {
  margin: 1.5rem 0; padding-left: 1.25rem;
  border-left: 2px solid var(--accent);
  font-family: var(--sans); font-size: 1rem; line-height: 1.6; color: var(--fg);
}
.hku-story__cite {
  display: block; font-size: 0.8125rem; color: var(--fg-muted);
  margin-top: 0.5rem; font-style: normal;
}

@media (max-width: 1100px) {
  .hku__wall { columns: 4; }
  .hkx__grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 900px) {
  .hku__wall { columns: 3; }
  .hku-story__grid { grid-template-columns: 1fr; }
  .hky-grid--tall { grid-template-columns: repeat(3, 1fr); }
  .hky-grid--mix  { columns: 2; }
  .hkv-grid { grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); }
}
@media (max-width: 560px) {
  .hku__wall { columns: 2; }
  .hkx__grid { grid-template-columns: 1fr; }
  .hky-grid--tall { grid-template-columns: repeat(2, 1fr); }
  .hky-grid--mix  { columns: 1; }
  .hkv-grid { grid-template-columns: repeat(auto-fill, minmax(105px, 1fr)); }
}

/* ── /reparasi-buku/ ────────────────────────────────────────────────────────
   The page that ranks. Multi-column throughout, because the first rebuild set
   everything to a 46ch measure on a 1170px container and left the right-hand
   60% of the screen empty — correct for running prose, wrong for a glossary
   of 63 terms and a four-way price comparison, which are reference material
   and should be scannable in columns. */
.hkr-midcta {
  padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline);
  text-align: center;
}
.hkr-midcta .hkh-h2 { margin-left: auto; margin-right: auto; }
.hkr-midcta .hkr-lede { margin-left: auto; margin-right: auto; max-width: 44ch; }

.hkr-page .hkp__body p,
.hkr-lede { max-width: 62ch; }

.hkr-tiers, .hkr-compare, .hkr-gloss {
  padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline);
}
.hkr-tiers__head, .hkr-compare__head { margin-bottom: 2rem; }
.hkr-lede {
  font-family: var(--sans); font-size: 1rem; line-height: 1.65;
  color: var(--fg-muted); margin: 0.75rem 0 0;
}

.hkr-tiers__grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.25rem; }
.hkr-tier { border-top: 2px solid var(--accent); padding-top: 1rem; }
.hkr-tier__n {
  font-family: var(--display); font-size: 1.25rem; font-weight: 400;
  color: var(--fg-heading, var(--fg)); margin: 0 0 0.5rem;
}
.hkr-tier__p {
  font-family: var(--display); font-size: 1.5rem; line-height: 1.1;
  color: var(--accent); margin: 0 0 0.75rem;
}
.hkr-tier__p span {
  display: block; font-family: var(--sans); font-size: 0.75rem;
  letter-spacing: 0.1em; text-transform: uppercase; color: var(--fg-muted);
  margin-top: 0.35rem;
}
.hkr-tier__d {
  font-family: var(--sans); font-size: 0.9375rem; line-height: 1.6;
  color: var(--fg-muted); margin: 0;
}

/* A hero whose H1 is a full sentence rather than a phrase. The measure opens
   up and the top of the type ramp comes down, so the line count stays at
   three instead of five. Scoped, because the short-title heroes are correct
   as they are. */
.hkh-hero--wide .hkh-hero__title {
  max-width: 24ch;
  font-size: clamp(2rem, 4.4vw, 3.5rem);
  line-height: 1.08;
}

/* ═══════════════════════════════════════════════════════════════════════════
   PREMIUM DETAIL — rhythm, and motion that has to earn its place
   ═══════════════════════════════════════════════════════════════════════════

   Measured before this block: /reparasi-buku/ ran 18 sections and 23,518px in
   which EVERY section had the same transparent background and only 2 of 18
   were full-bleed. One unbroken white column. That is the "big chunk of text"
   feeling — not a shortage of pictures (there are 57), a shortage of rhythm.

   The fix is not alternating bands. CLAUDE.md is explicit that nine coloured
   blocks read as stripes, and that is how the first homepage attempt failed.
   Two dark full-bleed moments, at the two calls to action, punctuate the
   column instead: one at ~51% and one at the close. Everything between them
   stays paper-white and hairline-ruled.

   ── the glow ───────────────────────────────────────────────────────────────
   Adapted from the pointer-reactive gradient in
   for-claude/from-codepen/gradient-bg. The original stacks six gradients in
   green, yellow, red and blue through `difference` and `overlay` blend modes;
   dropped whole, it would put a rainbow on an achromatic site. What survives
   is the mechanism — layered radial gradients whose centres track the pointer
   through two custom properties — repainted in the house palette: --ink as
   ground, leather tan as the warm bloom, one soft-light layer for depth.

   Degrades in the right direction. --posX and --posY default to 0, so with no
   JavaScript, no pointer, or a touch screen that never fires pointermove, the
   band is a still warm gradient rather than a black rectangle. */
.hkg-glow,
.hkr-midcta,
.hkh-close,
.hkfb-close {
  --x: calc(var(--posX, 0) * 1px);
  --y: calc(var(--posY, 0) * 1px);
  position: relative;
  isolation: isolate;
  background-color: var(--ink, #101018);
  background-image:
    radial-gradient(70% 110% at calc(50% + var(--x) * 0.6) calc(10% + var(--y) * 0.6),
                    rgba(138, 88, 60, 0.55), rgba(138, 88, 60, 0) 68%),
    radial-gradient(90% 120% at calc(12% - var(--x) * 0.35) calc(100% - var(--y) * 0.35),
                    rgba(216, 168, 127, 0.20), rgba(216, 168, 127, 0) 62%),
    radial-gradient(120% 90% at calc(100% - var(--x) * 0.25) calc(0% + var(--y) * 0.25),
                    rgba(64, 64, 82, 0.55), rgba(16, 16, 24, 0) 70%),
    linear-gradient(158deg, #17171f, #0b0b10);
  background-blend-mode: soft-light, normal, normal, normal;
  /* Long, because a fast follow reads as a gimmick and a slow one reads as
     depth. This is the whole difference between the two. */
  transition: background-position 600ms ease-out;
}

/* Full bleed from inside the 1170px measure. overflow-x: clip on the page —
   not hidden — because hidden creates a scroll container and would break any
   position: sticky inside it. 100vw includes the scrollbar, which is why the
   clip is required rather than merely tidy. */
/* THE CLIP GOES ON A FULL-WIDTH ANCESTOR, NEVER ON .hkh.
   .hkh is the 1170px measure. Putting overflow-x: clip there clipped the PAINT
   of every full-bleed child back to 1170 while getBoundingClientRect() went on
   reporting 1440 — because clip clips painting, not layout. Every measurement
   said the bleed worked and the screen said otherwise. Measure layout, look at
   paint.
   .jeg_container is already viewport-width, so clipping there costs nothing
   visible and still absorbs the scrollbar's worth of 100vw overhang. clip and
   not hidden: hidden creates a scroll container and would kill sticky. */
.jeg_container { overflow-x: clip; }

/* The hero's recipe, unchanged, because it is already verified at
   1440/1024/768/390 on this tree. Do not invent a second one.

   .hkg-bleed IS DOUBLED, the other two deliberately are not. A selector list
   is scored per selector, so this reads .hkg-bleed at (0,2,0) and leaves
   .hkr-midcta / .hkh-close at (0,1,0) exactly as they are verified today.

   The doubling is not cosmetic. .hkg-bleed's only users are <section>s inside
   <article class="hk-content">, and hkglobal.css carries
   `.hk-content article, .hk-content section { margin: 0 0 2rem }` at (0,1,1)
   — one class beats one class plus one type only if you count classes, so the
   utility lost and margin-left computed to 0. The band still measured 100vw
   and still painted a gradient, so nothing 404d, nothing errored and every
   number looked plausible; it simply started at the container's content edge
   and hung 159px off the right, where .jeg_main's overflow-x: clip ate it.
   That shipped on all 25 /for-business/ routes.
   .hkr-midcta and .hkh-close sit outside .hk-content and never hit this. */
.hkg-bleed.hkg-bleed,
.hkr-midcta,
.hkh-close {
  width: 100vw;
  margin-left: calc(50% - 50vw);
  padding-left: max(1.5rem, calc(50vw - var(--container, 1170px) / 2));
  padding-right: max(1.5rem, calc(50vw - var(--container, 1170px) / 2));
}

/* The two CTA bands ARE glow bands. Aliasing here rather than adding a class
   to markup is deliberate: /reparasi-buku/ is frozen, and a restyle that
   needs no content edit is exactly what the freeze is supposed to allow. */
.hkr-midcta, .hkh-close { }

/* Type on the dark band. --accent at #8A583C is only 3.54:1 on this ground;
   --accent-light is 9.83:1, which is the whole reason that token exists. */
:is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close) :is(.hkh-h2, h2, .hkq__rtier) { color: #FFFFFF; }
:is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close) .hkh-eyebrow { color: var(--accent-light, #D8A87F); }
:is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close) :is(.hkr-lede, .hkh-close__lede, .hkq__note, p) {
  color: rgba(255, 255, 255, 0.78);
}
:is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close) .hkh-btn--solid {
  background: #FFFFFF; color: var(--ink, #101018); border-color: #FFFFFF;
}
:is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close) .hkh-btn--solid:hover,
:is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close) .hkh-btn--solid:focus-visible {
  background: var(--accent-light, #D8A87F);
  border-color: var(--accent-light, #D8A87F);
  color: var(--ink, #101018);
}
:is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close) .hkh-btn--ghost {
  color: #FFFFFF; border-color: rgba(255, 255, 255, 0.45);
}
:is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close) .hkh-btn--ghost:hover { border-color: #FFFFFF; }

/* ── reveal on scroll ───────────────────────────────────────────────────────
   FALLBACK FIRST, the same inversion the nav uses. The hiding rule is scoped
   to html.hk-reveal, and only the script adds that class — so no JavaScript,
   a blocked file, or a throw anywhere in it all leave every section visible.
   Hiding content by default and relying on script to reveal it is how a page
   ends up blank, and 71% of this site's clicks are phones. */
@media (prefers-reduced-motion: no-preference) {
  /* Both halves carry the SAME :is() so the show rule cannot lose on
     specificity. It did: the hide rule was written
     `.hk-reveal .hkr-page > div[id]` (0,3,1) and the show rule
     `.hk-reveal .hkr-page > .is-in` (0,3,0), so the type+attribute selector
     outranked it. The trust band got the class, stayed at opacity 0, and
     shipped as a 730px white gap. Every <section> was fine — they matched at
     (0,2,1) and lost to the show rule — which is why exactly one element on
     the page was broken and the bug looked like anything but specificity. */
  .hk-reveal .hkr-page > :is(section, div[id]) {
    opacity: 0;
    transform: translate3d(0, 14px, 0);
    transition: opacity 620ms cubic-bezier(.22, .61, .36, 1),
                transform 620ms cubic-bezier(.22, .61, .36, 1);
    will-change: opacity, transform;
  }
  .hk-reveal .hkr-page > :is(section, div[id]).is-in {
    opacity: 1;
    transform: none;
    will-change: auto;
  }
}

/* ── photographs answer the pointer ─────────────────────────────────────────
   4% over half a second inside a clipped frame. Enough to feel alive, not
   enough to notice as an effect — and it tells a reader the frame is a real
   thing to look at rather than decoration. */
.hkr-dmg, .hkr-cmp__item, .hkr-tier, .hkx-who__item { overflow: clip; }
.hkr-dmg__img, .hkr-cmp__img, .hkr-tier__img,
.hkx-who__img, .hkr-gloss__lead, .hkr-ship__img {
  transition: transform 520ms cubic-bezier(.22, .61, .36, 1),
              filter 520ms ease;
}
.hkr-dmg:hover .hkr-dmg__img,
.hkr-cmp__item:hover .hkr-cmp__img,
.hkr-tier:hover .hkr-tier__img,
.hkx-who__item:hover .hkx-who__img { transform: scale(1.04); }

/* The tan rule over a tier card thickens under the pointer — the card's own
   accent doing the acknowledging, so no new colour enters the view. */
.hkr-tier { transition: border-top-color 220ms ease; border-top-width: 2px; }
.hkr-tier:hover { border-top-color: var(--accent-deep, #6E4429); }

/* Prices, turnarounds and statistics are compared down a column, so their
   digits have to sit on the same rails. Lato's proportional figures put
   "Rp 35.000" and "Rp 125.000" out of register in a four-up grid. */
.hkr-tier__p, .hkq__rmeta, .hkq__table td, .hkt__num, .hkh-step__n {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* The arrow moves, the text does not. */
.hkh-arrow::after { transition: transform 240ms cubic-bezier(.22, .61, .36, 1); }
.hkh-arrow:hover::after,
.hkh-arrow:focus-visible::after { transform: translateX(0.35em); }

/* One visible focus treatment for everything added here, keyboard only. */
.hkq__opt:focus-visible, .hkq__back:focus-visible,
.hkr-gloss__idx a:focus-visible, .hkg-glow, .hkr-midcta, .hkh-close a:focus-visible {
  outline: 2px solid var(--accent, #8A583C);
  outline-offset: 3px;
}
.hkg-glow a:focus-visible { outline-color: var(--accent-light, #D8A87F); }

@media (prefers-reduced-motion: reduce) {
  .hkg-glow, .hkr-dmg__img, .hkr-cmp__img, .hkr-tier__img, .hkx-who__img,
  .hkh-arrow::after { transition: none; }
  .hkr-dmg:hover .hkr-dmg__img, .hkr-cmp__item:hover .hkr-cmp__img,
  .hkr-tier:hover .hkr-tier__img, .hkx-who__item:hover .hkx-who__img,
  .hkh-arrow:hover::after { transform: none; }
}

/* ── /reparasi-buku/ hero ───────────────────────────────────────────────────
   The H1 here is 100 characters and it is not negotiable: it carries the
   query terms for a page at position 1.3. So the type ramps down to fit the
   sentence rather than the sentence being cut to fit the type. */
.hkr-hero__title {
  font-size: clamp(1.75rem, 3.3vw, 2.875rem);
  line-height: 1.14;
  max-width: 26ch;
}
.hkr-hero .hkh-hero__lede { max-width: 56ch; margin-bottom: 1.5rem; }

/* The pull quote is the owner's sentence and the reason people trust the
   page. It reads as a quotation, not as a caption. */
.hkr-hero__q {
  margin: 0 0 1.5rem;
  padding: 0.15rem 0 0.15rem 1.125rem;
  border-left: 2px solid var(--accent);
  max-width: 46ch;
}
.hkr-hero__q p {
  font-family: var(--display);
  font-size: clamp(1.0625rem, 1.5vw, 1.25rem);
  font-style: italic;
  line-height: 1.45;
  color: #FFFFFF;
  margin: 0;
}

.hkr-hero__iic {
  font-family: var(--sans);
  font-size: 0.9375rem;
  line-height: 1.6;
  color: rgba(255,255,255,0.78);
  max-width: 54ch;
  margin: 0 0 1.25rem;
}
/* The captured link was #4caf50 — stock Material green, the exact tell the
   restyle pass exists to remove. Tan is the house accent and clears AA on
   this ground. */
.hkr-hero__iic a { color: #D8A87F; text-decoration: underline; }
.hkr-hero__iic a:hover { color: #FFFFFF; }

.hkr-hero__rating {
  font-family: var(--sans);
  font-size: 0.9375rem;
  color: rgba(255,255,255,0.88);
  margin: 0 0 1.75rem;
}
.hkr-hero__rating b { font-weight: 700; color: #FFFFFF; }
.hkr-hero__stars { color: #E8B84B; letter-spacing: 0.08em; }

/* ── photographs in the tier cards and the four reasons ─────────────────────
   One ratio per role: 4:3 for both, cropped on the way in rather than by CSS,
   so the file that ships is the frame that shows. */
.hkr-tier__img, .hkx-who__img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  margin-bottom: 1rem;
}
/* The tier card's accent rule sits above the photo, not the heading. */
.hkr-tier:has(.hkr-tier__img) { padding-top: 0.875rem; }
.hkx-who--photo .hkx-who__item { display: flex; flex-direction: column; }

/* ── the four services, compared, with the damage that defines each ────────
   1:1 here rather than the 4:3 used by the tier cards: these are detail
   frames of one defect, and a square crop keeps the defect central. */
.hkr-cmp { display: grid; gap: 1.75rem 1.25rem; }
.hkr-cmp__img {
  display: block; width: 100%; height: auto;
  aspect-ratio: 1 / 1; object-fit: cover; margin-bottom: 1rem;
}
.hkr-cmp__t {
  font-family: var(--display); font-size: 1.1875rem; font-weight: 400;
  color: var(--fg-heading, var(--fg)); margin: 0 0 0.5rem;
}
.hkr-cmp__b {
  font-family: var(--sans); font-size: 0.9375rem; line-height: 1.6;
  color: var(--fg-muted); margin: 0;
}

/* A single lead frame above the four shipping reassurances. */
.hkr-ship__img {
  display: block; width: 100%; height: auto;
  aspect-ratio: 16 / 9; object-fit: cover; margin: 0 0 2rem;
}

/* ── risk reversal and the institutional lane ───────────────────────────────
   Same card grid as the four reasons; these are prose, so they get no
   photography and are deliberately quieter than the sections around them. */
.hkr-risk, .hkr-inst {
  padding: var(--hkh-gap) 0;
  border-bottom: 1px solid var(--hairline);
}
.hkr-inst__cta { margin: 2rem 0 0; }

/* ── glossary index ─────────────────────────────────────────────────────────
   Jump links across the top of a 2,932px reference block. Nothing is hidden;
   this only makes it possible to reach one group without reading four. */
.hkr-gloss__idx {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 0.75rem;
  margin: 0 0 2.25rem;
}
.hkr-gloss__idx a {
  display: inline-flex;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.5rem 0.875rem;
  border: 1px solid var(--hairline);
  border-radius: 0;
  font-family: var(--sans);
  font-size: 0.8125rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fg-muted);
  text-decoration: none;
  transition: border-color .15s ease, color .15s ease;
}
.hkr-gloss__idx a:hover, .hkr-gloss__idx a:focus-visible {
  border-color: var(--accent);
  color: var(--fg-heading, var(--fg));
}
.hkr-gloss__idx a span {
  font-size: 0.75rem;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}
/* The header is sticky, so an anchor lands the heading underneath it. */
.hkr-gloss__tier { scroll-margin-top: 6rem; }
.hkr-gloss__group + .hkr-gloss__group { margin-top: 3rem; }

/* One lead frame per tier group, as a BANNER not a plate. At 3:2 across the
   full 1122px column these four came to 748px each — 3,000px, 38% of the
   glossary, for four decorative photographs in a reference section. 3:1 with
   a ceiling keeps the punctuation and returns the height to the entries. */
.hkr-gloss__lead {
  display: block; width: 100%; height: auto;
  aspect-ratio: 3 / 1; max-height: 220px;
  object-fit: cover; object-position: center 55%;
  margin: 0 0 2rem;
}

/* ── the encyclopedia block ─────────────────────────────────────────────────
   Two columns of plate-beside-text entries — the dictionary arrangement.
   The previous version put a full-width square over a caption in three
   columns, which read as a gallery and pushed this one section to 8,106px,
   34% of the page. A 132px plate carries a torn spine perfectly well and the
   block becomes reference material you can scan. */
.hke {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.75rem clamp(1.75rem, 4vw, 3.5rem);
  margin: 0;
}
.hke__row {
  display: grid;
  grid-template-columns: 132px minmax(0, 1fr);
  gap: 1.125rem;
  align-items: start;
  padding-top: 1.25rem;
  border-top: 1px solid var(--hairline);
}
/* Entries without a photograph keep the text column aligned with the ones
   that have it — a ragged left edge down a reference list reads as a fault. */
.hke__fig { min-height: 1px; }
.hke__plate {
  display: block; width: 100%; height: auto;
  aspect-ratio: 1 / 1; object-fit: cover;
  transition: transform 520ms cubic-bezier(.22, .61, .36, 1);
}
.hke__row { overflow: clip; }
.hke__row:hover .hke__plate { transform: scale(1.05); }

.hke__t {
  font-family: var(--sans);
  font-size: 0.9375rem;
  font-weight: 700;
  color: var(--fg-heading, var(--fg));
  margin: 0 0 0.3rem;
  line-height: 1.35;
}
.hke__t .hkr-en {
  display: block;
  font-weight: 400;
  font-style: italic;
  color: var(--fg-muted);
  font-size: 0.875rem;
}
.hke__d {
  font-family: var(--sans);
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--fg-muted);
  margin: 0;
}

/* The citation. Quiet by default — it is provenance, not a call to action —
   and it earns the accent only under the pointer. */
.hke__ref {
  display: block;
  margin-top: 0.5rem;
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  color: var(--fg-muted);
  text-decoration: none;
  border-bottom: 1px solid var(--hairline);
  padding-bottom: 0.35rem;
  transition: color .15s ease, border-color .15s ease;
}
/* Literal glyph and a margin — no CSS hex escapes at all. SITE_CSS is a
   plain triple-quoted string, so Python eats a leading backslash-digit
   as an octal escape and emits a C0 control character with stray digits
   behind it. That shipped once as "SELENGKAPNYA 92" on every homepage
   tile, and writing this very comment reproduced it twice more: once in
   the arrow, once in the non-breaking space. Use the character. */
.hke__ref::before { content: "↗"; margin-right: 0.4em; color: var(--accent); }
.hke__ref:hover, .hke__ref:focus-visible {
  color: var(--accent); border-color: var(--accent);
}

/* ── the kamus: 275 quoted period definitions ───────────────────────────────
   Text only. Illustrating 275 entries would be a 40 MB page; the plates at the
   top are twelve CC0 photographs and are lazy-loaded. Two columns, run-in
   style — term, definition and year on one flowing line — which is how a real
   dictionary sets a long list and roughly halves the height a stacked layout
   would take. */
.hkency { padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline); }

.hkency__plates {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 0.75rem;
  margin: 2rem 0 0.75rem;
}
.hkency__pfig { margin: 0; }
.hkency__plate {
  display: block; width: 100%; height: auto;
  aspect-ratio: 3 / 4; object-fit: cover;
  background: var(--grey-1, #F4F4F6);
}
.hkency__pfig figcaption {
  margin-top: 0.35rem;
  font-family: var(--sans); font-size: 0.6875rem;
  letter-spacing: 0.04em; color: var(--fg-muted);
}
.hkency__pcredit {
  font-family: var(--sans); font-size: 0.8125rem; color: var(--fg-muted);
  margin: 0 0 2.25rem; max-width: 62ch;
}

.hkency__list {
  columns: 2;
  column-gap: clamp(1.75rem, 4vw, 3.5rem);
  font-family: var(--sans);
}
/* No letter headings and no A-Z strip: twenty-five boxes reading "A B C D E…"
   is a table of contents for the alphabet, and it split a two-column list into
   twenty-five ragged fragments. Alphabetical order plus the search box is the
   affordance; the headings were decoration pretending to be navigation. */
.hkency__e {
  font-size: 0.875rem; line-height: 1.55;
  margin: 0 0 0.7rem; break-inside: avoid;
  color: var(--fg-muted);
}
.hkency__t {
  font-style: normal; font-weight: 700;
  color: var(--fg-heading, var(--fg));
}
.hkency__t::after { content: " — "; font-weight: 400; color: var(--fg-muted); }
/* The Indonesian entries carry an English equivalent; the quoted period ones
   do not. Same row shape either way. */
.hkency__en { font-style: italic; color: var(--fg-muted); }
.hkency__en::after { content: " — "; font-style: normal; }
.hkency__ref {
  text-decoration: none; color: var(--accent); font-size: 0.8125rem;
  padding: 0 0.15rem;
}
.hkency__ref:hover, .hkency__ref:focus-visible { color: var(--fg-heading, var(--fg)); }
.hkency__s { font-size: 0.75rem; color: var(--accent); white-space: nowrap; }
.hkency__s::before { content: " ("; }
.hkency__s::after  { content: ")"; }

/* The filter box is inserted by JS. It is not in the markup, so a reader
   without JavaScript gets the whole list and no dead control. */
.hkency__filter {
  display: flex; align-items: baseline; gap: 0.75rem;
  margin: 0 0 1.25rem; font-family: var(--sans);
}
.hkency__filter input {
  flex: 1 1 auto; max-width: 22rem;
  font: inherit; font-size: 0.9375rem;
  padding: 0.6rem 0.875rem;
  border: 1px solid var(--hairline); border-radius: 0;
  background: var(--bg); color: var(--fg);
}
.hkency__filter input:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px;
}
.hkency__count { font-size: 0.8125rem; color: var(--fg-muted); }
.hkency__e[hidden] { display: none; }

@media (max-width: 900px) {
  .hkency__plates { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .hkency__list { columns: 1; }
}
@media (max-width: 480px) {
  .hkency__plates { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0.5rem; }
}

.hke__sources { margin-top: 3rem; padding-top: 2rem; border-top: 2px solid var(--accent); }
.hke__sources ol {
  margin: 1.5rem 0 0; padding-left: 1.25rem;
  font-family: var(--sans); font-size: 0.875rem; line-height: 1.7;
  color: var(--fg-muted); columns: 2; column-gap: clamp(1.75rem, 4vw, 3.5rem);
}
.hke__sources li { margin: 0 0 0.875rem; break-inside: avoid; }
.hke__sources a { color: var(--fg); text-decoration: underline; }
.hke__sources a:hover { color: var(--accent); }
.hke__rights { display: block; font-size: 0.8125rem; color: var(--fg-muted); }

@media (max-width: 900px) {
  .hke { grid-template-columns: 1fr; }
  .hke__sources ol { columns: 1; }
}
@media (max-width: 480px) {
  .hke__row { grid-template-columns: 96px minmax(0, 1fr); gap: 0.875rem; }
}
@media (prefers-reduced-motion: reduce) {
  .hke__plate { transition: none; }
  .hke__row:hover .hke__plate { transform: none; }
}

/* ── tier questionnaire ─────────────────────────────────────────────────────
   Two renderings of one decision tree. The table ships visible and is what a
   reader without JavaScript gets; .hkq__ui replaces it once it mounts. */
.hkq { padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline); }
.hkq__box {
  margin-top: 2rem;
  border: 1px solid var(--hairline);
  background: var(--bg-sunken, rgba(0,0,0,0.02));
}

.hkq__table { width: 100%; border-collapse: collapse; font-family: var(--sans); }
.hkq__table caption {
  text-align: left; padding: 1rem 1.25rem 0;
  font-size: 0.8125rem; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--fg-muted);
}
.hkq__table th, .hkq__table td {
  text-align: left; padding: 0.875rem 1.25rem; font-size: 0.9375rem;
  border-top: 1px solid var(--hairline); vertical-align: top;
}
.hkq__table th {
  font-size: 0.75rem; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--fg-muted); font-weight: 400;
}

.hkq__ui { padding: clamp(1.5rem, 3vw, 2.5rem); }
.hkq__count {
  font-family: var(--sans); font-size: 0.75rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--fg-muted); margin: 0 0 0.5rem;
}
.hkq__q {
  font-family: var(--display); font-size: clamp(1.25rem, 2.2vw, 1.75rem);
  line-height: 1.25; color: var(--fg-heading, var(--fg));
  margin: 0 0 1.5rem; max-width: 30ch;
}
.hkq__opts { display: grid; gap: 0.625rem; max-width: 34rem; }

/* Full-width rows, not chips: on a phone these must be unmissable taps.
   Minimum 48px tall via the padding + line-height, which is the touch target
   size the tier-3 checklist calls for. */
.hkq__opt {
  display: block; width: 100%; text-align: left; cursor: pointer;
  font-family: var(--sans); font-size: 1rem; line-height: 1.5;
  padding: 0.875rem 1.125rem;
  background: var(--bg, #FFFFFF); color: var(--fg);
  border: 1px solid var(--hairline); border-radius: 0;
  transition: border-color .15s ease, color .15s ease;
}
.hkq__opt:hover, .hkq__opt:focus-visible {
  border-color: var(--accent); color: var(--fg-heading, var(--fg));
}

.hkq__back {
  margin-top: 1.25rem; cursor: pointer;
  font-family: var(--sans); font-size: 0.8125rem; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--fg-muted);
  background: none; border: 0; border-radius: 0; padding: 0.5rem 0;
}
.hkq__back:hover, .hkq__back:focus-visible { color: var(--accent); }
.hkq__acts { display: flex; gap: 1.5rem; align-items: center; }

.hkq__rlabel {
  font-family: var(--sans); font-size: 0.75rem; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--fg-muted); margin: 0 0 0.5rem;
}
.hkq__rtier {
  font-family: var(--display); font-size: clamp(2rem, 4vw, 3rem);
  line-height: 1.05; color: var(--fg-heading, var(--fg)); margin: 0 0 0.5rem;
}
.hkq__rmeta {
  font-family: var(--sans); font-size: 1.0625rem; color: var(--accent);
  margin: 0 0 1rem;
}
.hkq__rdesc {
  font-family: var(--sans); font-size: 1rem; line-height: 1.65;
  color: var(--fg); margin: 0 0 0.75rem; max-width: 48ch;
}
.hkq__rsay {
  font-family: var(--sans); font-size: 0.9375rem; color: var(--fg-muted);
  margin: 0; max-width: 48ch;
}
.hkq__note {
  font-family: var(--sans); font-size: 0.875rem; line-height: 1.6;
  color: var(--fg-muted); margin: 1rem 0 1.75rem; max-width: 56ch;
}

@media (max-width: 767px) {
  .hkq__table caption, .hkq__table th, .hkq__table td { padding-left: 1rem; padding-right: 1rem; }
  .hkq__table thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .hkq__table td { display: block; border-top: 0; padding-top: 0.2rem; padding-bottom: 0.2rem; }
  .hkq__table tr { display: block; border-top: 1px solid var(--hairline); padding: 0.875rem 0; }
  .hkq__table td:first-child { padding-top: 0.875rem; }
}

/* Definition lists in columns. A 63-term glossary in one column is a scroll;
   in three it is a reference. */
.hkr-dl { margin: 0; display: grid; gap: 0 clamp(1.5rem, 3vw, 3rem); }
.hkr-dl--1 { grid-template-columns: 1fr; }
.hkr-dl--2 { grid-template-columns: repeat(2, 1fr); }

/* Materials and scope, side by side: two short lists that answer two
   different questions and should be readable without scrolling past one. */
.hkr-spec {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(1.5rem, 5vw, 4rem);
  padding: var(--hkh-gap) 0;
  border-bottom: 1px solid var(--hairline);
}
@media (max-width: 767px) { .hkr-spec { grid-template-columns: 1fr; } }
.hkr-dl--3 { grid-template-columns: repeat(3, 1fr); }
.hkr-dl__row { padding: 0.875rem 0; border-top: 1px solid var(--hairline); }
.hkr-dl dt {
  font-family: var(--sans); font-weight: 700; font-size: 0.9375rem;
  color: var(--fg); margin-bottom: 0.3rem;
}
.hkr-dl dd {
  margin: 0; font-family: var(--sans); font-size: 0.875rem;
  line-height: 1.55; color: var(--fg-muted);
}
.hkr-en {
  font-weight: 400; font-style: italic; color: var(--fg-muted);
  font-size: 0.8125rem;
}
.hkr-gloss__tier {
  font-family: var(--sans); font-size: 0.75rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--accent);
  margin: 2.25rem 0 0.25rem; padding-top: 1.25rem;
  border-top: 2px solid var(--accent);
}
.hkr-note { display: block; font-size: 0.75rem; color: var(--fg-muted); margin-top: 0.2rem; }
.hkr-steps { grid-template-columns: repeat(4, 1fr) !important; }

@media (max-width: 900px) {
  .hkr-tiers__grid { grid-template-columns: repeat(2, 1fr); }
  .hkr-dl--3 { grid-template-columns: repeat(2, 1fr); }
  .hkr-steps { grid-template-columns: repeat(2, 1fr) !important; }
}
@media (max-width: 560px) {
  .hkr-tiers__grid, .hkr-dl--2, .hkr-dl--3 { grid-template-columns: 1fr; }
  .hkr-steps { grid-template-columns: 1fr !important; }
  /* The illustrated glossary keeps two columns on a phone. Collapsed to one
     it is 19 full-width squares and the page measured 40,212px — reference
     material should not be most of the scroll. Two columns halve it and the
     frames stay large enough to read a torn spine at ~165px. */
  .hkr-dl--photo { grid-template-columns: repeat(2, 1fr); gap: 1.75rem 1rem; }
  .hkr-dl--photo dt { font-size: 0.9375rem; }
  .hkr-dl--photo dd { font-size: 0.8125rem; }
}

/* ── /custom-notebook/ ──────────────────────────────────────────────────────
   Reuses the homepage primitives (hkh-btn, hkh-h2, hkh-steps, hkh-faq) and
   adds only what this page needs. Nothing here declares a colour of its own. */
/* This page's hero photograph is a BRIGHT flatlay, not the dark workshop shot
   the homepage uses, so the shared bottom-weighted veil left white type on a
   near-white background. Weight it to the left instead, over the text column. */
.hkc .hkh-hero__veil {
  background: linear-gradient(to right,
    rgba(16,16,24,0.92) 0%, rgba(16,16,24,0.80) 38%,
    rgba(16,16,24,0.45) 68%, rgba(16,16,24,0.20) 100%);
}

.hkc-badge { margin: 1.75rem 0 0; }
.hkc-badge__img {
  display: block; width: auto; max-width: 300px; height: auto;
  border: 1px solid rgba(255,255,255,0.18);
}

.hkc-clients { padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline); }
.hkc-clients__head { margin-bottom: 2.25rem; }
.hkc-clients__grid {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: clamp(1.25rem, 2.5vw, 2rem);
}
.hkc-client { margin: 0; }
.hkc-client__frame {
  display: block; aspect-ratio: 1 / 1; overflow: hidden;
  background: var(--paper, #F4F2EF); margin-bottom: 0.875rem;
}
.hkc-client__img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .5s cubic-bezier(.2,.7,.3,1);
}
.hkc-client:hover .hkc-client__img { transform: scale(1.04); }
.hkc-client__name {
  font-family: var(--sans); font-size: 0.8125rem; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--fg-muted);
}

.hkc-mat { padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline); }
.hkc-mat__head { margin-bottom: 2.25rem; }
.hkc-mat__grid {
  display: grid; grid-template-columns: repeat(2, 1fr);
  gap: clamp(2rem, 4vw, 3.5rem);
}
.hkc-mat__frame {
  display: block; aspect-ratio: 16 / 10; overflow: hidden;
  background: var(--paper, #F4F2EF); margin-bottom: 1.25rem;
}
.hkc-mat__img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hkc-mat__term {
  font-family: var(--display); font-weight: 400; font-size: 1.375rem;
  color: var(--fg-heading, var(--fg)); margin: 0 0 0.5rem;
}
.hkc-mat__body {
  font-family: var(--sans); font-size: 0.9375rem; line-height: 1.65;
  color: var(--fg-muted); margin: 0; max-width: 42ch;
}

.hkc-steps4 { grid-template-columns: repeat(4, 1fr); }
.hkc-steps4 .hkh-step__frame { display: none; }
.hkc-steps4 .hkh-step__n { border-top: 2px solid var(--accent); padding-top: 0.875rem; }

/* The gallery. Small frames on purpose: these are 540-1024px source files and
   a large tile would show every one of their limits. */
.hkc-gal { padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline); }
.hkc-gal__head { margin-bottom: 2rem; }
.hkc-gal__grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 0.75rem;
}
.hkc-gal__frame {
  display: block; aspect-ratio: 1 / 1; overflow: hidden;
  background: var(--paper, #F4F2EF);
}
.hkc-gal__img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .4s cubic-bezier(.2,.7,.3,1);
}
.hkc-gal__frame:hover .hkc-gal__img { transform: scale(1.06); }

@media (max-width: 900px) {
  .hkc-clients__grid { grid-template-columns: repeat(2, 1fr); }
  .hkc-mat__grid { grid-template-columns: 1fr; }
  .hkc-steps4 { grid-template-columns: repeat(2, 1fr); }
  .hkc-gal__grid { grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); }
}
@media (max-width: 480px) {
  .hkc-clients__grid { grid-template-columns: 1fr; }
  .hkc-steps4 { grid-template-columns: 1fr; }
}

/* ── /hibrkraft-experience/ ─────────────────────────────────────────────────
   Reuses the shared primitives; adds a schedule list and a two-tier price
   block. Both tiers are square, and the featured one is marked with a rule
   and a label rather than a colour fill — one accent per view still holds. */
/* The tour group stands on the RIGHT of this frame, so the veil is weighted
   left: the text column darkens, the people stay visible. A uniform darkening
   would have cost the one thing this photograph is for. Measured after, against
   the brightest quartile behind each: H1 8.97:1, lede 9.70:1. */
.hkx .hkh-hero__veil {
  background: linear-gradient(to right,
    rgba(16,16,24,0.90) 0%, rgba(16,16,24,0.78) 34%,
    rgba(16,16,24,0.42) 62%, rgba(16,16,24,0.14) 100%);
}

.hkx-docs { padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline); }
.hkx-docs__head { margin-bottom: 2rem; }
.hkx-docs__grid {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: clamp(0.75rem, 1.5vw, 1.25rem);
}
.hkx-doc {
  display: block; aspect-ratio: 1 / 1; overflow: hidden;
  background: var(--paper, #F4F2EF);
}
.hkx-doc__img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform .5s cubic-bezier(.2,.7,.3,1);
}
.hkx-doc:hover .hkx-doc__img { transform: scale(1.04); }

.hkx-from {
  font-family: var(--sans); font-size: 0.8125rem; letter-spacing: 0.06em;
  color: rgba(255,255,255,0.72); margin: 1.5rem 0 0;
}

.hkx-who { padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline); }
.hkx-who__head { margin-bottom: 2.25rem; }
.hkx-who__grid {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: clamp(1.5rem, 3vw, 2.5rem);
}
.hkx-who__item { border-top: 2px solid var(--accent); padding-top: 1rem; }
.hkx-who__term {
  font-family: var(--display); font-weight: 400; font-size: 1.1875rem;
  color: var(--fg-heading, var(--fg)); margin: 0 0 0.5rem;
}
.hkx-who__body {
  font-family: var(--sans); font-size: 0.9375rem; line-height: 1.6;
  color: var(--fg-muted); margin: 0;
}

.hkx-sched { padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline); }
.hkx-sched__head { margin-bottom: 1.5rem; }
.hkx-sched__list { list-style: none; margin: 0; padding: 0; }
.hkx-step {
  display: flex; gap: clamp(1.25rem, 3vw, 3rem);
  padding: 1.5rem 0; border-top: 1px solid var(--hairline);
}
.hkx-step__min {
  flex: 0 0 5.5rem; font-family: var(--display); font-size: 2rem;
  line-height: 1; color: var(--accent);
}
.hkx-step__unit {
  display: block; font-family: var(--sans); font-size: 0.6875rem;
  letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--fg-muted); margin-top: 0.35rem;
}
.hkx-step__body { flex: 1 1 auto; }
.hkx-step__t {
  display: block; font-family: var(--display); font-size: 1.25rem;
  color: var(--fg-heading, var(--fg)); margin-bottom: 0.375rem;
}
.hkx-step__b {
  display: block; font-family: var(--sans); font-size: 0.9375rem;
  line-height: 1.65; color: var(--fg-muted); max-width: 56ch;
}

.hkx-tiers { padding: var(--hkh-gap) 0; border-bottom: 1px solid var(--hairline); }
.hkx-tiers__head { margin-bottom: 2.25rem; }
.hkx-tiers__grid {
  display: grid; grid-template-columns: repeat(2, 1fr);
  gap: clamp(1.5rem, 3vw, 2.5rem); align-items: start;
}
.hkx-tier {
  position: relative; border: 1px solid var(--hairline);
  padding: clamp(1.75rem, 3vw, 2.5rem);
}
.hkx-tier--featured { border-color: var(--accent); }
.hkx-tier__tag {
  position: absolute; top: 0; left: 0;
  transform: translateY(-50%);
  margin-left: clamp(1.75rem, 3vw, 2.5rem);
  background: var(--accent); color: #FFFFFF;
  font-family: var(--sans); font-size: 0.6875rem; letter-spacing: 0.12em;
  text-transform: uppercase; padding: 0.35rem 0.7rem;
}
.hkx-tier__name {
  font-family: var(--sans); font-size: 0.8125rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--fg-muted); margin: 0 0 0.75rem;
}
.hkx-tier__price {
  font-family: var(--display); font-size: clamp(1.75rem, 3vw, 2.375rem);
  line-height: 1; color: var(--fg-heading, var(--fg)); margin: 0 0 1rem;
}
.hkx-tier__unit {
  display: block; font-family: var(--sans); font-size: 0.8125rem;
  letter-spacing: 0.04em; color: var(--fg-muted); margin-top: 0.5rem;
}
.hkx-tier__blurb {
  font-family: var(--sans); font-size: 0.9375rem; line-height: 1.65;
  color: var(--fg-muted); margin: 0 0 1.5rem; max-width: 40ch;
}
/* Hairline ticks, not coloured check-mark emoji. The captured page used ✔️,
   which renders as a full-colour glyph in an interface that is otherwise
   achromatic — and the purge had already replaced 304 emoji images elsewhere
   for the same reason. */
.hkx-tier__list { list-style: none; margin: 0 0 1.75rem; padding: 0; }
.hkx-tier__list li {
  position: relative; padding: 0.5rem 0 0.5rem 1.5rem;
  border-top: 1px solid var(--hairline);
  font-family: var(--sans); font-size: 0.9375rem; line-height: 1.55;
  color: var(--fg);
}
.hkx-tier__list li::before {
  content: "—"; position: absolute; left: 0; color: var(--accent);
}
.hkx-tier__cta { margin: 0; }

@media (max-width: 900px) {
  .hkx-who__grid { grid-template-columns: repeat(2, 1fr); }
  .hkx-docs__grid { grid-template-columns: repeat(2, 1fr); }
  .hkx-tiers__grid { grid-template-columns: 1fr; gap: 2.5rem; }
  .hkx-step { flex-direction: column; gap: 0.75rem; }
  .hkx-step__min { flex: none; display: flex; align-items: baseline; gap: 0.5rem; }
  .hkx-step__unit { margin-top: 0; }
}
@media (max-width: 480px) {
  .hkx-who__grid { grid-template-columns: 1fr; }
}

/* ── Hibrkraft Experience ────────────────────────────────────────────────── */
.hkh-invite {
  position: relative; width: 100vw; margin-left: calc(50% - 50vw);
  overflow: hidden; isolation: isolate;
  min-height: min(56vh, 480px); display: flex; align-items: center;
}
.hkh-invite__img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; z-index: -2;
}
.hkh-invite__veil {
  position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(to right,
    rgba(16,16,24,0.90) 0%, rgba(16,16,24,0.72) 48%, rgba(16,16,24,0.35) 100%);
}
.hkh-invite__inner {
  width: 100%; max-width: var(--container, 1170px);
  margin: 0 auto; padding: clamp(2.5rem, 5vw, 4rem) 1.5rem;
}
.hkh-invite .hkh-h2 { color: #FFFFFF; }
.hkh-invite .hkh-eyebrow { color: #D8A87F; }
.hkh-invite__lede { color: rgba(255,255,255,0.90) !important; }
.hkh-invite__note { color: rgba(255,255,255,0.66) !important; }
.hkh-invite .hkh-btn--outline { color: #FFFFFF; border-color: rgba(255,255,255,0.6); }
.hkh-invite .hkh-btn--outline:hover { background: #FFFFFF; color: #101018; border-color: #FFFFFF; }
.hkh-invite__lede {
  font-family: var(--sans);
  font-size: 1.0625rem;
  line-height: 1.7;
  color: var(--fg);
  max-width: 48ch;
  margin: 0 0 1rem;
}
.hkh-invite__note {
  font-family: var(--sans);
  font-size: 0.9375rem;
  line-height: 1.65;
  color: var(--fg-muted);
  max-width: 48ch;
  margin: 0 0 1.75rem;
}

.hkh-btn--outline {
  color: var(--fg);
  border-color: var(--fg);
  background: transparent;
}
.hkh-btn--outline:hover,
.hkh-btn--outline:focus-visible { background: var(--fg); color: var(--bg, #FFFFFF); }

/* ── close ───────────────────────────────────────────────────────────────── */
.hkh-close { padding: var(--hkh-gap) 0; text-align: center; }
.hkh-close .hkh-h2 { margin-left: auto; margin-right: auto; }
.hkh-close__lede {
  font-family: var(--sans);
  font-size: 1.0625rem;
  line-height: 1.65;
  color: var(--fg-muted);
  max-width: 44ch;
  margin: 0 auto 2rem;
}

@media (max-width: 900px) {
  .hkh-doors { grid-template-columns: 1fr; }
  .hkh-door { border-left: 0; }
  .hkh-split { grid-template-columns: 1fr; }
  .hkh-split--flip .hkh-split__media { order: 0; }
  .hkh-journal__grid { grid-template-columns: 1fr; }
  .hkh-journal__head { flex-direction: column; align-items: flex-start; gap: 0.75rem; }
  .hkh-hero { min-height: 68vh; }
}

@media (max-width: 560px) {
  .hkh-gloss__list { grid-template-columns: 1fr; }
}

@media (max-width: 480px) {
  .hkh-btn { display: block; text-align: center; }
  .hkh-btn + .hkh-btn { margin-left: 0; margin-top: 0.75rem; }
}

@media (prefers-reduced-motion: reduce) {
  .hkh-door__img, .hkh-post__img { transition: none; }
  .hkh-door:hover .hkh-door__img, .hkh-post:hover .hkh-post__img { transform: none; }
}

.hk-press-source {
  font-family: var(--sans);
  font-size: 0.8125rem;
  line-height: 1.6;
  color: var(--fg-muted);
  margin: 2.5rem 0 0;
  padding-top: 1rem;
  border-top: 1px solid var(--hairline);
}

/* ── /hibrkraft-world/templates/ — the printable paper section ───────────────
 *
 * Base is .hkm. Checked against every stylesheet in the tree before naming it,
 * not just this file: site.css holds b c e g h p q r s t u v w x y, nav-v2 has
 * n, footer-v2 has f, and the page-local sheets hold a d j k z. That left
 * i l m o, and .hkd was ALREADY taken by content/glossary/page.css — a grep of
 * site.css alone would have missed it and silently restyled the glossary.
 * See css-base-collision in tools/verify.py.
 *
 * It lives here rather than in content/<route>/page.css because 28 pages share
 * it and page.css is INLINED, not linked. Twenty-eight copies of 4 KB, none of
 * them cacheable, to save one request that is already being made.
 *
 * Every value is a token. Nothing new is invented.
 * ------------------------------------------------------------------------- */

/* ── the sheet, wherever it appears ──────────────────────────────────────────
 * These previews are rendered from the PDFs, so they are line art on white.
 * A hairline and a faint shadow are what make a white rectangle on a white
 * page read as a sheet of paper rather than as a hole in the layout. */
.hkm-hero__img,
.hkm-card__img {
  display: block;
  width: 100%;
  height: auto;
  background: var(--paper);
  border: 1px solid var(--hairline);
}

/* ── hero: text beside the sheet ─────────────────────────────────────────── */
.hkm-hero {
  display: grid;
  gap: 2.5rem;
  grid-template-columns: 1fr;
  align-items: center;
  padding: 2.5rem 0 3rem;
  border-bottom: 1px solid var(--hairline);
}
@media (min-width: 900px) {
  .hkm-hero { grid-template-columns: 1fr minmax(0, 420px); gap: 4rem; }
}

.hkm-hero__title {
  font-family: var(--display);
  font-size: clamp(2rem, 5vw, 3.1rem);
  line-height: 1.1;
  color: var(--fg-heading);
  margin: 0.5rem 0 0;
}
.hkm-hero__lede {
  font-family: var(--sans);
  font-size: 1.0625rem;
  line-height: 1.65;
  color: var(--fg);
  max-width: 34em;
  margin: 1.1rem 0 0;
}
.hkm-hero__use {
  font-family: var(--sans);
  font-size: 0.9375rem;
  line-height: 1.6;
  color: var(--fg-muted);
  max-width: 34em;
  margin: 0.7rem 0 0;
}
.hkm-hero__cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.25rem;
  margin: 1.75rem 0 0;
}
.hkm-hero__alt {
  font-family: var(--sans);
  font-size: var(--t-sm);
  letter-spacing: 0.04em;
  color: var(--accent);
}

/* The four facts under the button. A row of small caps, hairline-separated —
 * the same device the trust band uses, at a smaller scale. */
.hkm-hero__facts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.4rem;
  margin: 1.5rem 0 0;
  padding-top: 1rem;
  border-top: 1px solid var(--hairline);
  font-family: var(--sans);
  font-size: var(--t-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-muted);
}

.hkm-hero__sheet { margin: 0; }

/* A planner shows two: the inside page large, the cover behind it and smaller.
 * The inside is what a reader has to answer "will I write on this?" with, so
 * it leads; the cover is what the file looks like, so it follows. */
.hkm-hero__pair {
  display: grid;
  grid-template-columns: 1.55fr 1fr;
  gap: 1.25rem;
  align-items: start;
}
.hkm-hero__cap {
  font-family: var(--sans);
  font-size: var(--t-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-muted);
  margin-top: 0.6rem;
}

/* ── section heads, shared by hub and kind pages ─────────────────────────── */
.hkm-sec__head { margin-bottom: 1.9rem; max-width: 46em; }
.hkm-sec__blurb {
  font-family: var(--sans);
  font-size: 0.9375rem;
  line-height: 1.65;
  color: var(--fg-muted);
  margin: 0.6rem 0 0;
}

.hkm-sizes,
.hkm-print,
.hkm-rel,
.hkm-sec,
.hkm-intro,
.hkm-lic { padding: 3.25rem 0; border-bottom: 1px solid var(--hairline); }

/* ── the download table ──────────────────────────────────────────────────────
 * The table IS the content of a kind page. It ships visible, it is a real
 * <table> with a real <thead>, and it stays usable at 390px by scrolling in
 * its own box rather than by collapsing into cards — a five-row table that
 * becomes twenty stacked divs is harder to scan, not easier. */
.hkm-tablewrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.hkm-table {
  width: 100%;
  border-collapse: collapse;
  font-family: var(--sans);
  min-width: 34rem;
}
.hkm-table th,
.hkm-table td {
  text-align: left;
  vertical-align: middle;
  padding: 1rem 1rem 1rem 0;
  border-bottom: 1px solid var(--hairline);
}
.hkm-table thead th {
  font-size: var(--t-micro);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--fg-muted);
  font-weight: 400;
  padding-bottom: 0.6rem;
}
.hkm-table tbody tr:last-child th,
.hkm-table tbody tr:last-child td { border-bottom: 0; }

.hkm-size {
  display: block;
  font-family: var(--display);
  font-size: 1.25rem;
  color: var(--fg-heading);
  font-weight: 400;
}
.hkm-size__note {
  display: block;
  font-size: var(--t-micro);
  line-height: 1.5;
  color: var(--fg-muted);
  margin-top: 0.25rem;
  max-width: 16em;
}
.hkm-mm {
  font-size: 0.8125rem;
  color: var(--fg-muted);
  white-space: nowrap;
}
.hkm-none { color: var(--fg-muted); }

.hkm-dl {
  display: inline-block;
  text-decoration: none;
  border: 1px solid var(--ink);
  padding: 0.6rem 1rem;
  color: var(--fg-heading);
  background: transparent;
  white-space: nowrap;
}
.hkm-dl:hover { background: var(--ink); color: var(--paper); }
.hkm-dl:hover .hkm-dl__size { color: var(--paper); }
.hkm-dl__label {
  display: block;
  font-size: var(--t-sm);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.hkm-dl__size {
  display: block;
  font-size: var(--t-micro);
  color: var(--fg-muted);
  margin-top: 0.15rem;
}
/* The English file is the same sheet in another language, not another
 * product. It is offered, not promoted: hairline border, no fill on hover. */
.hkm-dl--alt { border-color: var(--hairline); }
.hkm-dl--alt:hover { background: transparent; color: var(--accent); border-color: var(--accent); }
.hkm-dl--alt:hover .hkm-dl__size { color: var(--fg-muted); }

/* ── printing steps ──────────────────────────────────────────────────────── */
.hkm-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: 1.6rem; }
.hkm-steps > li { display: flex; gap: 1.1rem; align-items: flex-start; }
.hkm-steps__n {
  flex: 0 0 auto;
  font-family: var(--display);
  font-size: 1.5rem;
  line-height: 1;
  color: var(--accent);
  width: 1.6rem;
}
.hkm-steps__h {
  font-family: var(--sans);
  font-size: 0.9375rem;
  letter-spacing: 0.02em;
  color: var(--fg-heading);
  margin: 0 0 0.3rem;
}
.hkm-steps > li p {
  font-family: var(--sans);
  font-size: 0.9375rem;
  line-height: 1.65;
  color: var(--fg-muted);
  margin: 0;
  max-width: 38em;
}
@media (min-width: 760px) {
  .hkm-steps--row { grid-template-columns: repeat(3, 1fr); gap: 2rem; }
}

/* ── the hub index strip ─────────────────────────────────────────────────── */
.hkm-index { padding: 2.5rem 0; border-bottom: 1px solid var(--hairline); }
.hkm-index__grid { display: grid; gap: 1rem; grid-template-columns: repeat(2, 1fr); }
@media (min-width: 760px) { .hkm-index__grid { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1000px) { .hkm-index__grid { grid-template-columns: repeat(6, 1fr); } }
.hkm-idx {
  display: block;
  text-decoration: none;
  border: 1px solid var(--hairline);
  border-left: 2px solid var(--accent);
  padding: 1rem 1.1rem;
  color: var(--fg);
}
.hkm-idx:hover { border-color: var(--accent); }
.hkm-idx__n {
  display: block;
  font-family: var(--display);
  font-size: 1.5rem;
  line-height: 1;
  color: var(--fg-heading);
}
.hkm-idx__name {
  display: block;
  font-family: var(--sans);
  font-size: var(--t-micro);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--fg-muted);
  margin-top: 0.4rem;
}

.hkm-intro__text {
  font-family: var(--sans);
  font-size: 1.0625rem;
  line-height: 1.7;
  color: var(--fg);
  max-width: var(--measure);
}
.hkm-intro__text p { margin: 0 0 1rem; }
.hkm-intro__text p:last-child { margin-bottom: 0; }

/* ── the kind card ───────────────────────────────────────────────────────── */
.hkm-grid {
  display: grid;
  gap: 2rem 1.5rem;
  grid-template-columns: repeat(2, 1fr);
}
@media (min-width: 760px)  { .hkm-grid { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 1000px) { .hkm-grid { grid-template-columns: repeat(4, 1fr); } }

.hkm-card { display: block; text-decoration: none; color: var(--fg); min-width: 0; }
.hkm-card__frame {
  display: block;
  overflow: hidden;
  background: var(--grey-1);
  margin-bottom: 0.85rem;
}
.hkm-card__img { transition: transform 0.35s ease; }
.hkm-card:hover .hkm-card__img { transform: scale(1.03); }
.hkm-card__body { display: block; }
.hkm-card__name {
  display: block;
  font-family: var(--display);
  font-size: 1.0625rem;
  line-height: 1.3;
  color: var(--fg-heading);
}
.hkm-card:hover .hkm-card__name { color: var(--accent); }
.hkm-card__use {
  display: block;
  font-family: var(--sans);
  font-size: 0.8125rem;
  line-height: 1.55;
  color: var(--fg-muted);
  margin-top: 0.35rem;
}
.hkm-card__meta {
  display: block;
  font-family: var(--sans);
  font-size: var(--t-micro);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--fg-muted);
  margin-top: 0.5rem;
}

.hkm-rel__all { margin: 1.75rem 0 0; font-family: var(--sans); font-size: 0.9375rem; }

/* ── licence ─────────────────────────────────────────────────────────────── */
.hkm-lic__inner {
  font-family: var(--sans);
  font-size: 0.9375rem;
  line-height: 1.7;
  color: var(--fg-muted);
  max-width: var(--measure);
}
.hkm-lic__inner p { margin: 0.5rem 0 0; }
.hkm-lic__inner a { color: var(--accent); }

/* ── the close ───────────────────────────────────────────────────────────────
 * The one commercial ask on the page, and the reason these files exist: the
 * workshop that binds books also makes the paper that goes in them. Dark, so
 * it reads as the end of the document rather than as another section. */
.hkm-close {
  background: var(--ink);
  color: var(--fg-dark);
  padding: 3.75rem 0;
  width: 100vw;
  margin-left: calc(50% - 50vw);
}
.hkm-close__inner {
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 1.25rem;
}
.hkm-close .hkh-eyebrow { color: var(--accent-light); }
.hkm-close .hkh-h2 { color: #FFFFFF; }
.hkm-close__lede {
  font-family: var(--sans);
  font-size: 1.0625rem;
  line-height: 1.7;
  color: var(--fg-dark);
  max-width: 40em;
  margin: 0.9rem 0 0;
}
.hkm-close__cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.5rem;
  margin: 1.9rem 0 0;
}
/* #8A583C is only 3.54:1 on #101018 — the accent token flips to #D8A87F in
 * the dark block for exactly this reason, and this band is dark in BOTH
 * themes, so it names the light accent directly rather than inheriting one
 * that is only correct half the time. */
.hkm-close__cta .hkh-arrow { color: var(--accent-light); }

/* ---------------------------------------------------------------------------
 * Utilities for the 21 enriched /for-business/ leaves.
 *
 * Those pages carried 1,177 style attributes the page builder left behind.
 * 962 of them were these fourteen declarations repeated, so they are classes
 * now and the markup carries none. This is a move, not a redesign: the bar was
 * pixel-identical rendering, verified by screenshot at 1440 and 390.
 *
 * The 215 attributes that remain are the ones a machine could not prove safe
 * to touch — hero overlay veils, absolute positioning, per-page grid widths.
 * They are left exactly as they were. An element was only ever rewritten when
 * EVERY declaration on it was recognised.
 *
 * Two of these are corrections rather than moves, and both are deliberate:
 *
 *   .hk-bd  the captured border was a hardcoded #ccc. It is var(--hairline)
 *           here, which is #E4E4E8 in day and #2A2A2A in dark. Slightly
 *           lighter than #ccc, and it is the reason these tables stop being
 *           unreadable the moment someone switches to the dark theme.
 *
 *   .hk-onimg  white type, used only where it sits over photography. Kept as
 *           a literal because that is what it is: a colour tied to an image
 *           behind it, not to the theme.
 *
 * WHY EVERY RULE HERE IS !important
 *
 * Each of these replaced an INLINE declaration, and an inline declaration
 * outranks every author rule in the 45 vendored stylesheets. Drop it into a
 * plain class and it silently loses to whatever the theme already said. That
 * is not hypothetical — it happened on the first pass and was measured:
 *
 *     .hk-p12    56/56 cells rendered 8px, because
 *                body:not(.jnews-disable-style-table) .entry-content td
 *                is (0,2,2) and .hk-p12 is (0,1,0). The table lost 132px
 *                of height and nobody would have noticed from the markup.
 *     .hk-bd     56/56 cells lost their border the same way.
 *     .hk-onimg  a <p> over a dark band went from white to #212121 —
 *                near-invisible text, the worst kind of silent regression.
 *
 * So !important here is not an escalation, it is the faithful translation of
 * the precedence the markup already had. The same reasoning covers media
 * queries: an inline style overrode the theme's responsive rules before this
 * change, so a class that did not would be the behaviour change.
 *
 * The two markers below are read by tools/verify.py (utility-precedence). Only
 * rules BETWEEN them are held to the !important rule — the rest of this file
 * is components like .hk-press-*, which style markup the generator creates and
 * have no inline declaration to outrank. Move a rule out of this block and it
 * stops being checked, so keep new inline-replacement utilities inside it.
 * ------------------------------------------------------------------------- */
/* @inline-replacement-utilities: start */

.hk-tc { text-align: center !important; }
.hk-tl { text-align: left !important; }

.hk-fg   { color: var(--fg) !important; }
.hk-fgh  { color: var(--fg-heading) !important; }
.hk-fgm  { color: var(--fg-muted) !important; }
.hk-ac   { color: var(--accent) !important; }
.hk-ac-i { color: var(--accent) !important; }

.hk-onimg { color: #FFFFFF !important; }

.hk-uc { text-transform: uppercase !important; }

.hk-bd  { border: 1px solid var(--hairline) !important; }
.hk-p12 { padding: 12px !important; }

/* The accent table header. The captured markup said
 * `<tr style="background-color:#8A583C; color:white">`, but a colour
 * INHERITED from tr loses to any theme rule that names th directly — and
 * jnews names it. So the header shipped as #53585C on #8A583C: 1.21:1,
 * against a 4.5 floor. It was not a design decision, it was a defeat, and it
 * predates this pass; the author had already asked for white.
 *
 * The descendant rule is the fix. Setting colour on the row alone would lose
 * the same argument all over again. */
.hk-bg-accent { background-color: var(--accent) !important; }
.hk-bg-accent th, .hk-bg-accent td { color: #FFFFFF !important; }

/* @inline-replacement-utilities: end */

/* ── /press/ ─────────────────────────────────────────────────────────────────
 * The press room. Base is `.hkpr`, four letters, NOT `.hkp` — that base is
 * already taken by the section block used on /reviews/, and a second
 * top-level rule on a base that is in use does not fail, it silently restyles
 * the other one everywhere it appears. That is the .hkb collision recorded in
 * CLAUDE.md, which put a 100vw full-bleed rule on the breadcrumb of all 866
 * pages and took counting elements in a rendered DOM to find.
 *
 * Declares no colour, face or measure of its own: every value below maps off
 * tokens.css, so the dark theme follows for free and theme-contrast keeps
 * covering it. Section rhythm copies the rest of the page kit exactly —
 * var(--hkh-gap) and a hairline, never an alternating background band. Nine
 * coloured blocks read as stripes; that is how the first homepage failed.
 * ────────────────────────────────────────────────────────────────────────── */

.hkpr-fast,
.hkpr-kit,
.hkpr-sec,
.hkpr-origin,
.hkpr-voices,
.hkpr-award,
.hkpr-method,
.hkpr-notes {
  padding: var(--hkh-gap) 0;
  border-bottom: 1px solid var(--hairline);
}

.hkpr__lede {
  font-family: var(--sans);
  font-size: 1.0625rem;
  line-height: 1.6;
  color: var(--fg);
  max-width: 46ch;
  margin: 0 0 2rem;
}

.hkpr__sub {
  font-family: var(--sans);
  font-size: var(--t-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fg-muted);
  margin: 2.5rem 0 1rem;
}

.hkpr__note {
  font-family: var(--sans);
  font-size: 0.875rem;
  line-height: 1.65;
  color: var(--fg-muted);
  max-width: 60ch;
  margin: 1.5rem 0 0;
}

.hkpr__note a { color: var(--accent); }

/* The footnote marker. `sup` on its own shifts the line box and opens a ragged
   gap above every row that carries one, so the offset is done with a negative
   top on an inline-block instead of by superscript positioning. */
.hkpr__fn {
  font-size: 0.6875rem;
  line-height: 1;
  vertical-align: super;
  margin-left: 0.2em;
}

.hkpr__fn a {
  color: var(--accent);
  text-decoration: none;
  padding: 0 0.15em;
}

.hkpr__fn a:hover,
.hkpr__fn a:focus-visible { text-decoration: underline; }

/* ── the ten-second summary ───────────────────────────────────────────────── */

.hkpr-fast__list { margin: 0; }

.hkpr-fast__row {
  display: grid;
  grid-template-columns: minmax(6rem, 11ch) 1fr;
  gap: 0 2rem;
  padding: 0.9rem 0;
  border-top: 1px solid var(--hairline);
}

.hkpr-fast__row dt {
  font-family: var(--sans);
  font-size: var(--t-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fg-muted);
  padding-top: 0.25rem;
}

.hkpr-fast__row dd {
  margin: 0;
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.6;
  color: var(--fg);
}

@media (max-width: 640px) {
  .hkpr-fast__row { grid-template-columns: 1fr; gap: 0.35rem; }
  .hkpr-fast__row dt { padding-top: 0; }
}

/* ── press kit ────────────────────────────────────────────────────────────── */

.hkpr-kit__grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1px;
  background: var(--hairline);
  border: 1px solid var(--hairline);
}

.hkpr-kit__i { display: flex; }

.hkpr-kit__a {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  width: 100%;
  padding: 1.5rem 1.25rem;
  background: var(--bg);
  text-decoration: none;
  transition: background-color 120ms ease;
}

.hkpr-kit__a:hover,
.hkpr-kit__a:focus-visible { background: var(--grey-1, #F4F4F6); }

.hkpr-kit__t {
  font-family: var(--display);
  font-size: 1.125rem;
  line-height: 1.2;
  color: var(--fg-heading);
}

.hkpr-kit__d {
  font-family: var(--sans);
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--fg);
  flex: 1;
}

.hkpr-kit__m {
  font-family: var(--sans);
  font-size: var(--t-micro);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent);
}

@media (max-width: 900px) { .hkpr-kit__grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 520px) { .hkpr-kit__grid { grid-template-columns: 1fr; } }

/* ── the citation lists ───────────────────────────────────────────────────── */

.hkpr-list { list-style: none; margin: 0; padding: 0; }

.hkpr-list__i {
  padding: 0.85rem 0;
  border-top: 1px solid var(--hairline);
}

.hkpr-list__a,
.hkpr-list__t {
  display: inline;
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.5;
  color: var(--fg-heading);
}

.hkpr-list__a { text-decoration: none; border-bottom: 1px solid var(--accent); }

.hkpr-list__a:hover,
.hkpr-list__a:focus-visible { color: var(--accent); }

/* An archive row is a record, not a link, and must not read as one. */
.hkpr-list--plain .hkpr-list__t { color: var(--fg); }

.hkpr-list__m {
  display: block;
  margin-top: 0.25rem;
  font-family: var(--sans);
  font-size: var(--t-micro);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fg-muted);
}

/* ── the clippings ────────────────────────────────────────────────────────── */

.hkpr-klip {
  list-style: none;
  margin: 0 0 2.5rem;
  padding: 0;
  display: grid;
  gap: 1.5rem;
  max-width: 46rem;
}

.hkpr-klip__img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--hairline);
  /* The clippings are screenshots of other people's pages, always on their own
     white ground. In the dark theme an untreated white block glares, so it is
     dimmed slightly rather than inverted — inverting would misrepresent the
     outlet's own typesetting, which is the only reason to show a clipping. */
  background: #FFFFFF;
}

:root[data-theme="dark"] .hkpr-klip__img { opacity: 0.88; }

.hkpr-klip__cap {
  display: block;
  margin-top: 0.5rem;
  font-family: var(--sans);
  font-size: var(--t-micro);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fg-muted);
}

/* ── award and method: prose beside a photograph ──────────────────────────── */

.hkpr-award,
.hkpr-method {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}

.hkpr-method__img,
.hkpr-award__img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover;
}

.hkpr-method__img { aspect-ratio: 1 / 1; }

.hkpr-award__t {
  font-family: var(--display);
  font-size: clamp(1.25rem, 2vw, 1.5rem);
  line-height: 1.2;
  color: var(--fg-heading);
  margin: 0 0 0.35rem;
}

.hkpr-award__m {
  font-family: var(--sans);
  font-size: var(--t-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 1.25rem;
}

.hkpr-award__body p,
.hkpr-method__body p {
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.65;
  color: var(--fg);
  max-width: 46ch;
}

@media (max-width: 860px) {
  .hkpr-award,
  .hkpr-method { grid-template-columns: 1fr; }
  /* Photograph after the prose on a phone: the text is why the section exists,
     and 71% of this site's clicks are phones. */
  .hkpr-award__img,
  .hkpr-method__img { order: 2; }
}

/* ── a quotation ─────────────────────────────────────────────────────────────
   A quote on this page is evidence, so it is set as a citation rather than as
   decoration: no oversized punctuation glyph, no italic, a rule on the leading
   edge, and the attribution always visible beneath it. A pull-quote whose
   source you have to hunt for is a poster, not a citation.
   Every value maps off tokens.css; nothing here declares a colour of its own. */
.hkpr-q {
  margin: 1.75rem 0;
  padding: 0 0 0 1.5rem;
  border-left: 2px solid var(--accent);
}

.hkpr-q p {
  font-family: var(--display);
  font-size: clamp(1.0625rem, 1.6vw, 1.25rem);
  line-height: 1.5;
  color: var(--fg-heading);
  margin: 0 0 0.75rem;
  max-width: 42ch;
}

.hkpr-q__by {
  display: block;
  font-family: var(--sans);
  font-size: var(--t-micro);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--fg-muted);
  line-height: 1.5;
}

.hkpr-q__by a {
  color: var(--fg-muted);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.hkpr-q__by a:hover,
.hkpr-q__by a:focus-visible { color: var(--accent); }

/* ── the first coverage: prose beside the print edition ──────────────────────
   The same two-column arrangement as .hkpr-award. The photograph is a picture
   OF PAPER, not a screenshot on a white ground, so it takes neither
   .hkpr-klip__img's white background nor its dark-theme dimming — newsprint is
   already off-white, and dimming it would read as a bad exposure rather than
   as a considered treatment. */
.hkpr-origin {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(2rem, 5vw, 4rem);
  align-items: start;
}

.hkpr-origin__fig { margin: 0; }

.hkpr-origin__img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border: 1px solid var(--hairline);
}

.hkpr-origin__cap {
  display: block;
  margin-top: 0.75rem;
  font-family: var(--sans);
  font-size: 0.8125rem;
  line-height: 1.55;
  color: var(--fg-muted);
}

/* Direct children only, and notes and the lede excluded by :not(), so those two
   keep the styling their own class gives them. A bare `.hkpr-origin__body p`
   is (0,1,1) and would quietly outrank .hkpr__note at (0,1,0) — which is how
   .hkpr-method__body already swallows the note sitting inside it. */
/* 60ch, not the 46ch the award body uses: here the grid column IS the measure
   at ~553px, so a 46ch cap left a 120px hole between the prose and the
   photograph and dropped the line to about 55 characters. This barely binds at
   1170 and only catches if the column ever grows. */
.hkpr-origin__body > p:not(.hkpr__note):not(.hkpr__lede) {
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.65;
  color: var(--fg);
  max-width: 60ch;
}

@media (max-width: 860px) {
  .hkpr-origin { grid-template-columns: 1fr; }
  /* Prose first on a phone: the quotations are why the section exists, and
     71% of this site's clicks are phones. */
  .hkpr-origin__fig { order: 2; }
}

/* ── what they wrote ─────────────────────────────────────────────────────── */

/* Multi-column, not grid. A two-column GRID aligns rows to the tallest cell,
   so a one-line quote beside a five-line one leaves a visible hole; quotations
   of uneven length want packing. `role="list"` is on the markup because
   list-style: none drops list semantics in VoiceOver. */
.hkpr-voices__list {
  list-style: none;
  margin: 0;
  padding: 0;
  columns: 2;
  column-gap: clamp(2rem, 4vw, 3.5rem);
}

.hkpr-voices__i {
  break-inside: avoid;
  -webkit-column-break-inside: avoid;
}

.hkpr-voices__i .hkpr-q { margin: 0 0 2.25rem; }

@media (max-width: 760px) {
  .hkpr-voices__list { columns: 1; }
}

/* Where the outside record and our own numbers disagree. Same two-column
   arrangement as the ten-second summary, one shade quieter, because this is a
   caveat rather than a headline. */
.hkpr-diff { margin: 1.25rem 0 0; }

.hkpr-diff__row {
  display: grid;
  grid-template-columns: minmax(7rem, 14ch) 1fr;
  gap: 0 2rem;
  padding: 0.9rem 0;
  border-top: 1px solid var(--hairline);
}

.hkpr-diff__row dt {
  font-family: var(--sans);
  font-size: var(--t-micro);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--fg-muted);
  padding-top: 0.25rem;
}

/* Capped, unlike .hkpr-fast__row dd, which needs none because its values are a
   few words. These run two or three sentences and without a measure they set
   to the full 1170px container — about 145 characters a line, twice the top of
   the readable band. */
.hkpr-diff__row dd {
  margin: 0;
  font-family: var(--sans);
  font-size: 0.9375rem;
  line-height: 1.65;
  color: var(--fg);
  max-width: 70ch;
}

@media (max-width: 640px) {
  .hkpr-diff__row { grid-template-columns: 1fr; gap: 0.35rem; }
  .hkpr-diff__row dt { padding-top: 0; }
}

/* ── footnotes ────────────────────────────────────────────────────────────── */

.hkpr-notes__list {
  margin: 0;
  padding-left: 1.25rem;
  max-width: 62ch;
}

.hkpr-notes__i {
  font-family: var(--sans);
  font-size: 0.875rem;
  line-height: 1.65;
  color: var(--fg-muted);
  padding: 0.5rem 0;
}

.hkpr-notes__i a { color: var(--accent); }

.hkpr-notes__back { text-decoration: none; margin-left: 0.35rem; }

/* ── canvas: keep a chart inside its column on a phone ───────────────────────
 *
 * Nine of the top-40 blog posts embed a live Chart.js canvas sized
 * `width: 768px; height: 768px` inline. The page does not scroll sideways —
 * measured at 390px, scrollWidth == clientWidth on all four samples — because
 * the theme caps the figures around it. The CANVAS is not capped, so on a
 * 390px screen the chart is simply cut off at the column edge, and 71% of this
 * site's clicks are phones.
 *
 * height:auto with width capped keeps the aspect ratio Chart.js drew at.
 * ------------------------------------------------------------------------- */
.entry-content canvas { max-width: 100%; height: auto; }

/* ── .hkpdf — the print-edition download offered at the foot of an article ───
 *
 * Base is .hkpdf — two or more letters, which is the convention for anything
 * new since /press/ shipped .hkpr-*. It says what it is, and it cannot collide
 * with a bare .hk<letter> base by construction, because `.hkpdf` does not
 * match `\.hk[a-z](?![\w-])`. Single letters are for the sixteen load-bearing
 * bases already spread across 899 pages.
 *
 * AN EARLIER VERSION OF THIS COMMENT CLAIMED THE .hk<letter> NAMESPACE WAS
 * EXHAUSTED. That was wrong, and it was wrong in the exact way CLAUDE.md warns
 * about, one section below the rule it broke. The audit behind it was
 * `grep -rhoE '\.hk[a-z]\b'` over the raw file, which makes two mistakes:
 *
 *     \b matches at a hyphen, so `.hkg-glow` is scored as base `g`
 *     comments are not stripped, so the header reading "Base is .hkd"
 *       three blocks above is scored as a declaration of .hkd
 *
 * Together they reported .hkd, .hkg and .hkm as taken when none is a bare
 * base. Re-measured correctly — strip every CSS comment first, then match
 * `\.hk([a-z])(?![\w-])` — the global sheets reserve
 *
 *     b c e f h n p q r s t u v w x y      (16 reserved)
 *     a d g i j k l m o z                  (10 FREE for a new global base)
 *
 * So css-base-collision matching `^\.hk[a-z]$` is the CORRECT scope, not a
 * blind spot: a prefixed name never participates in the collision the rule is
 * about. Do not "fix" that check on the strength of the claim I made here.
 *
 * It lives here rather than in content/<route>/page.css  because every wired post shares
 * it and page.css is INLINED, not linked — 40 uncacheable copies of the same
 * rule to save a request that is already being made. See the delivery rule.
 *
 * Every value is a token. Nothing new is invented.
 * ------------------------------------------------------------------------- */
.hkpdf {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem 1.5rem;
  margin: 2.5rem 0 0;
  padding: 1.25rem 1.5rem;
  border: 1px solid var(--hairline);
  border-left: 3px solid var(--accent);
  background: var(--bg);
}
.hkpdf__body { flex: 1 1 16rem; min-width: 0; }
.hkpdf__label {
  font-family: var(--sans);
  font-size: 0.6875rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 0.35rem;
}
.hkpdf__title {
  font-family: var(--display);
  font-size: 1.0625rem;
  line-height: 1.3;
  color: var(--fg-heading);
  margin: 0 0 0.25rem;
}
.hkpdf__meta {
  font-family: var(--sans);
  font-size: 0.8125rem;
  color: var(--fg-muted);
  margin: 0;
}
.hkpdf__cta {
  font-family: var(--sans);
  font-size: 0.8125rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 0.75rem 1.5rem;
  border: 1px solid var(--ink);
  border-radius: 0;              /* the measured button spec */
  background: var(--ink);
  color: #FFFFFF;
  text-decoration: none;
  white-space: nowrap;
}
.hkpdf__cta:hover { background: var(--accent); border-color: var(--accent); }

/* ── .hklib — the shelf: several full-length PDFs offered on one page ────────
 *
 * Base is .hklib. Three letters after hk, so it consumes none of the ten free
 * bare .hk<letter> bases and cannot collide with one by construction — the
 * audit pattern does not match a prefixed name. Same reasoning as .hkpdf and
 * .hkpr before it.
 *
 * Distinct from .hkpdf directly above, which is the single-file card an
 * article carries at its foot. This one is a shelf. The books it offers run
 * 92 to 182 A5 pages and 1.7 to 11.7 MB, so a reader is agreeing to something
 * before they click and the card says what: a cover, the title the file itself
 * carries, what it is about, and the weight.
 *
 * It lives here rather than in a route's own page.css because two routes share
 * it and page.css is INLINED, not linked — two uncacheable copies of the same
 * rule to save a request that is already being made. See the delivery rule.
 *
 * NO `download` attribute on these anchors, and that is a decision rather than
 * an oversight. downloads/.htaccess sets Content-Disposition inline so the
 * files open in the browser's own viewer; that is what a 92-page book wants,
 * and it is what lets Googlebot render a file it has been told to index.
 * Forcing a save to disk would defeat both, and these are meant to rank.
 *
 * Every value is a token. Nothing new is invented.
 * ------------------------------------------------------------------------- */
.hklib { margin: 3.5rem 0 0; }
.hklib__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: 2.5rem 1.75rem;
  margin: 2rem 0 0;
}
.hklib__card {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.hklib__frame {
  display: block;
  margin: 0 0 1.125rem;
  border: 1px solid var(--hairline);
  background: var(--grey-1);
  line-height: 0;
}
.hklib__img {
  display: block;
  width: 100%;
  height: auto;
}
.hklib__label {
  font-family: var(--sans);
  font-size: 0.6875rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 0.4rem;
}
.hklib__title {
  font-family: var(--display);
  font-size: 1.125rem;
  line-height: 1.3;
  color: var(--fg-heading);
  margin: 0 0 0.5rem;
}
.hklib__title a { color: inherit; text-decoration: none; }
.hklib__title a:hover { color: var(--accent); text-decoration: underline; }
.hklib__desc {
  font-family: var(--sans);
  font-size: 0.875rem;
  line-height: 1.6;
  color: var(--fg);
  margin: 0 0 0.75rem;
}
.hklib__meta {
  font-family: var(--sans);
  font-size: 0.75rem;
  letter-spacing: 0.04em;
  color: var(--fg-muted);
  margin: 0 0 1.125rem;
}
.hklib__cta {
  font-family: var(--sans);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  align-self: flex-start;
  margin-top: auto;
  padding: 0.7rem 1.25rem;
  border: 1px solid var(--ink);
  border-radius: 0;              /* the measured button spec */
  background: var(--ink);
  color: #FFFFFF;
  text-decoration: none;
}
.hklib__cta:hover { background: var(--accent); border-color: var(--accent); }
.hklib__note {
  font-family: var(--sans);
  font-size: 0.8125rem;
  line-height: 1.6;
  color: var(--fg-muted);
  margin: 2rem 0 0;
  padding: 0 0 0 1rem;
  border-left: 1px solid var(--hairline);
}

/* ── .hkpg — the consolidated product gallery ────────────────────────────────
 *
 * Twelve product families were listed 173 times between them; they are now 105
 * pages, and this block is where the retired listings' photographs go. The
 * merge ADDS what those pages showed rather than discarding it — 80 frames
 * across the twelve canonicals.
 *
 * Base is .hkpg: two letters, which is the convention for anything new since
 * /press/ shipped .hkpr-*. It cannot collide with a bare .hk<letter> base by
 * construction, because `.hkpg` does not match \.hk[a-z](?![\w-]).
 *
 * In site.css and not content/<route>/page.css because twelve pages share it
 * and page.css is INLINED, not linked — twelve uncacheable copies to save a
 * request that is already being made.
 *
 * Every value is a token.
 * ------------------------------------------------------------------------- */
.hkpg {
  margin: 3rem 0 0;
  padding-top: 2rem;
  border-top: 1px solid var(--hairline);
}
.hkpg__h {
  font-family: var(--display);
  font-size: 1.375rem;
  line-height: 1.25;
  color: var(--fg-heading);
  margin: 0 0 0.5rem;
}
.hkpg__lede {
  font-family: var(--sans);
  font-size: 0.9375rem;
  color: var(--fg-muted);
  margin: 0 0 1.5rem;
  max-width: 46em;
}
.hkpg__facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: 0.75rem 2rem;
  margin: 0 0 2rem;
  padding: 1rem 0;
  border-top: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
}
.hkpg__r dt {
  font-family: var(--sans);
  font-size: 0.6875rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 0.25rem;
}
.hkpg__r dd {
  font-family: var(--sans);
  font-size: 0.9375rem;
  color: var(--fg);
  margin: 0;
}
.hkpg__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
  gap: 0.75rem;
}
.hkpg__f { margin: 0; }
/* 1:1 — every product photograph in this catalogue is 540x540, so the ratio is
   the source's, not a crop invented here. */
.hkpg__f img {
  display: block;
  width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  background: var(--grey-1, #F4F4F6);
}

/* ── .hkac — accordion, native <details> ────────────────────────────────────
 *
 * Replaces WPBakery's vc_tta tabs on the /for-business/ pages. The panels ship
 * with `open`, so the content is readable with no JavaScript and no stylesheet
 * at all — the same inversion the nav and the glossary filter use. That is what
 * makes js_composer_tta.min.css (262 KB, 2,652 rules, 0 of them in
 * hkglobal.css) unnecessary on those routes.
 *
 * Base is .hkac: two letters, the convention for anything new.
 * Every value is a token.
 * ------------------------------------------------------------------------- */
.hkac { border-top: 1px solid var(--hairline); margin: 0; }
.hkac:last-of-type { border-bottom: 1px solid var(--hairline); }
.hkac > summary {
  cursor: pointer;
  list-style: none;
  padding: 1rem 2rem 1rem 0;
  position: relative;
  font-family: var(--display);
  font-size: 1.0625rem;
  line-height: 1.35;
  color: var(--fg-heading);
}
.hkac > summary::-webkit-details-marker { display: none; }
.hkac > summary::after {
  content: "+";
  position: absolute;
  right: 0.25rem;
  top: 50%;
  transform: translateY(-50%);
  font-family: var(--sans);
  font-size: 1.25rem;
  color: var(--accent);
}
.hkac[open] > summary::after { content: "–"; }
.hkac > summary:hover { color: var(--accent); }
.hkac__body { padding: 0 0 1.25rem; }
.hkac__body > *:first-child { margin-top: 0; }
.hkac__body > *:last-child { margin-bottom: 0; }


/* A YouTube facade with no poster. Used where no thumbnail was ever fetched;
   the frame still has to hold 16:9 so the page does not jump on click. */
.hky__link--noposter .hky__frame {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  aspect-ratio: 16 / 9; background: var(--ink, #101018); color: #FFFFFF;
  text-decoration: none;
}
.hky__link--noposter .hky__play { font-size: 2.5rem; line-height: 1; }
.hky__link--noposter .hky__cap {
  font-family: var(--sans); font-size: .875rem; letter-spacing: .04em;
  margin-top: .6rem; text-decoration: underline;
}
.hky__link--noposter .hky__frame iframe { width: 100%; height: 100%; border: 0; }

/* ── .hk-catnav — the way back up, on a /glossary-cat/ page ──────────────────
   Added 2026-08-11 with the category rebuild. Before it, the taxonomy was a
   set of dead ends: a reader who reached a category could not get to the hub,
   to a sibling category, or to the other 96-of-6 terms. There was no link back
   anywhere on the page.

   Two-plus letters in the base by design. The single-letter .hk<x> namespace
   is down to ten free letters across the global sheets, and a bare .hk<letter>
   may be declared by exactly one top-level rule — see css-base-collision. A
   multi-letter base cannot collide with a bare one by construction, which is
   the convention /press/ (.hkpr-*) established.

   No colour, face or measure is declared here that tokens.css does not own. */
.hk-catnav {
  margin-top: 3rem; padding-top: 1.5rem;
  border-top: 1px solid var(--hairline);
}
.hk-catnav__lead {
  font-family: var(--sans); font-size: .875rem; letter-spacing: .02em;
  color: var(--fg-muted); margin: 0 0 .75rem;
}
.hk-catnav ul {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: .5rem .75rem;
}
.hk-catnav li { margin: 0; }
.hk-catnav li a {
  font-family: var(--sans); font-size: .8125rem; letter-spacing: .04em;
  text-transform: uppercase; text-decoration: none;
  border: 1px solid var(--hairline); padding: .45rem .7rem;
  display: inline-block;
}
.hk-catnav li a:hover, .hk-catnav li a:focus-visible {
  border-color: var(--ink); background: var(--ink); color: var(--paper);
}
/* The member count rides after the link, outside it, so the tap target is the
   name and not the digits. */
.hk-catnav li span {
  font-family: var(--sans); font-size: .75rem; color: var(--fg-muted);
  margin-left: .15rem;
}

/* ═══════════════════════════════════════════════════════════════════════════
   .hkfb — the /for-business/ tree: one hub, four L1 hubs, twenty L2 leaves
   ═══════════════════════════════════════════════════════════════════════════

   Two-letter base on purpose. The single-letter namespace ran out at 16 and
   the audit pattern for it is \.hk([a-z])(?![\w-]), which does not match
   .hkfb-hero — so this family consumes none of the ten remaining letters.
   Same convention /press/ established with .hkpr.

   It lives in site.css rather than in twenty-five copies of page.css because
   twenty-five routes share it. A page.css is inlined into every response, so
   a shared block put there is paid for on every page view and cached on none.

   ── the veil ──────────────────────────────────────────────────────────────
   One veil, tuned for the BRIGHTEST photograph in the set rather than the
   average one. The frames behind these heroes range from near-black studio
   shots to a pale tan flatlay, and a veil that suits the mean leaves the
   bright ones with white type at roughly 2.7:1 — which is what the tree
   shipped. Tuning to the worst case costs the dark frames a little contrast
   they can afford and costs the bright ones nothing they cannot.
   Left-and-down weighted, because the copy sits bottom-left. */

.hkfb-hero .hkh-hero__veil {
  background:
    linear-gradient(90deg,
      rgba(16, 16, 24, 0.94) 0%, rgba(16, 16, 24, 0.86) 34%,
      rgba(16, 16, 24, 0.42) 68%, rgba(16, 16, 24, 0.16) 100%),
    linear-gradient(0deg,
      rgba(16, 16, 24, 0.74) 0%, rgba(16, 16, 24, 0.34) 52%,
      rgba(16, 16, 24, 0.14) 100%);
}
/* Below 780px the copy occupies the full width, so a left-weighted gradient
   leaves the last line of the H1 on whatever the photograph has at the right
   edge. The gradient has to follow where the text actually is. */
@media (max-width: 780px) {
  .hkfb-hero .hkh-hero__veil {
    background: linear-gradient(0deg,
      rgba(16, 16, 24, 0.94) 0%, rgba(16, 16, 24, 0.88) 45%,
      rgba(16, 16, 24, 0.62) 72%, rgba(16, 16, 24, 0.30) 100%);
  }
}
/* --accent is 1.4-2.3:1 over these grounds even veiled. --accent-light is the
   token that exists for type on a photograph. */
.hkfb-hero .hkh-eyebrow { color: var(--accent-light, #D8A87F); }

/* An L2 title is a full sentence with a colon in it, not a phrase. The type
   ramps down to fit the sentence rather than the sentence being cut. */
.hkfb-hero .hkh-hero__title {
  font-size: clamp(1.75rem, 3.4vw, 2.875rem);
  line-height: 1.12;
  max-width: 26ch;
}

/* The one-line answer to "where am I and what does this page do", directly
   under the lede. Facts only — quantity, lead time, who it is for. */
.hkfb-hero__facts {
  display: flex; flex-wrap: wrap; gap: 0 2rem;
  list-style: none; margin: 0 0 2rem; padding: 0; max-width: 60ch;
}
.hkfb-hero__facts li {
  font-family: var(--sans); font-size: 0.8125rem; letter-spacing: 0.06em;
  text-transform: uppercase; color: rgba(255, 255, 255, 0.82);
  padding: 0.35rem 0;
}
.hkfb-hero__facts b {
  display: block; font-size: 1.375rem; letter-spacing: 0;
  text-transform: none; color: #FFFFFF; font-family: var(--display);
  font-weight: 400;
}

/* ── section rhythm ───────────────────────────────────────────────────────
   Sections separated by a hairline, never by alternating colour blocks. Nine
   coloured bands read as stripes; that is how the first homepage failed. */
/* padding-block, NOT the `padding` shorthand. This rule used to read
   `padding: clamp(…) 0 0`, and that horizontal `0` silently overwrote
   .hkg-bleed's gutters on every section carrying both classes — same
   specificity (0,1,0), later in the file, so it won. A shorthand sets four
   sides whether or not you meant to name them. */
.hkfb-s { padding-block: clamp(2.75rem, 6vw, 4.5rem) 0; }
.hkfb-s + .hkfb-s { border-top: 1px solid var(--hairline); }
.hkfb-s > :is(h2, .hkh-h2) { margin-top: 0; }
.hkfb-lede {
  font-family: var(--sans); font-size: 1.0625rem; line-height: 1.65;
  color: var(--fg); max-width: 60ch;
}

/* ── the child grid on an L1 hub ──────────────────────────────────────────
   Each card is one L2, and the label says what that page's single job is. */
.hkfb-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.75rem; margin: 2rem 0 0; }
.hkfb-grid--2 { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 900px) { .hkfb-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .hkfb-grid, .hkfb-grid--2 { grid-template-columns: 1fr; } }

/* (0,2,1). A bare .hkfb-card is (0,1,0) and the theme's .entry-content a
   underline rule is (0,2,0), so the first version shipped every card title
   AND its whole blurb underlined — text-decoration inherits from the anchor,
   so it has to be cancelled on the descendants too, not just the link. */
:is(.hkfb-grid, .hk-content, .hkfb-s) a.hkfb-card { display: block; text-decoration: none; }
:is(.hkfb-grid, .hk-content, .hkfb-s) a.hkfb-card:hover,
:is(.hkfb-grid, .hk-content, .hkfb-s) a.hkfb-card:focus-visible { text-decoration: none; }
:is(.hkfb-grid, .hk-content, .hkfb-s) a.hkfb-card :is(.hkfb-card__label, .hkfb-card__t, .hkfb-card__d) {
  text-decoration: none;
}
.hkfb-card__frame {
  display: block; aspect-ratio: 4 / 5; overflow: hidden;
  background: var(--grey-1, #F4F4F6); margin-bottom: 1rem;
}
.hkfb-card__frame img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* These are <span>s inside the card's <a>, so each needs display:block —
   an inline box ignores margin-bottom and runs the label, title and blurb
   together into a single paragraph. */
.hkfb-card__label {
  display: block;
  font-family: var(--sans); font-size: 0.6875rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--accent); margin: 0 0 0.4rem;
}
.hkfb-card__t {
  display: block;
  font-family: var(--display); font-size: 1.25rem; line-height: 1.2;
  color: var(--fg-heading, #101018); margin: 0 0 0.5rem;
}
.hkfb-card:hover .hkfb-card__t { color: var(--accent); }
.hkfb-card__d {
  display: block;
  font-family: var(--sans); font-size: 0.9375rem; line-height: 1.55;
  color: var(--fg-muted); margin: 0;
}

/* ── spec / comparison table ──────────────────────────────────────────────
   A real <table> so it is readable with styles off and by a screen reader.
   It scrolls inside its own container: the page body must never scroll. */
.hkfb-tw { overflow-x: auto; margin: 1.75rem 0 0; }
.hkfb-t { width: 100%; border-collapse: collapse; font-family: var(--sans); font-size: 0.9375rem; }
.hkfb-t th, .hkfb-t td {
  text-align: left; padding: 0.85rem 1rem 0.85rem 0;
  border-bottom: 1px solid var(--hairline); vertical-align: top; line-height: 1.5;
}
.hkfb-t thead th {
  font-size: 0.6875rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--fg-muted); border-bottom: 1px solid var(--fg-heading, #101018);
  white-space: nowrap;
}
.hkfb-t tbody th { font-weight: 400; color: var(--fg-heading, #101018); }
.hkfb-t td { color: var(--fg); }

/* ── numbered process ─────────────────────────────────────────────────────── */
.hkfb-steps { list-style: none; counter-reset: s; margin: 1.75rem 0 0; padding: 0; }
.hkfb-step {
  counter-increment: s; position: relative;
  padding: 1.35rem 0 1.35rem 3.5rem; border-top: 1px solid var(--hairline);
}
.hkfb-step::before {
  content: counter(s, decimal-leading-zero); position: absolute; left: 0; top: 1.35rem;
  font-family: var(--display); font-size: 1.125rem; color: var(--accent);
}
.hkfb-step h3 {
  font-family: var(--display); font-size: 1.1875rem; line-height: 1.25;
  color: var(--fg-heading, #101018); margin: 0 0 0.35rem;
}
.hkfb-step p { font-family: var(--sans); font-size: 0.9375rem; line-height: 1.6; color: var(--fg); margin: 0; max-width: 62ch; }

/* ── the closing band ─────────────────────────────────────────────────────
   Aliased into the glow family in the PREMIUM DETAIL block, so it inherits
   the pointer-reactive ground and the light-on-dark type rules rather than
   restating them. */
.hkfb-close { padding-block: clamp(2.75rem, 6vw, 4.5rem); }
/* (0,2,0), and it has to be. hkglobal.css carries
   `.hk-content article, .hk-content section { margin: 0 0 2rem }` at (0,1,1),
   which outranks a bare .hkfb-close and was zeroing this margin-top on all 25
   /for-business/ routes. The band also separates itself — it is near-black —
   so the .hkfb-s + .hkfb-s hairline is dropped rather than drawn in #E4E4E8
   across the top of it. */
.hkfb-s.hkfb-close { margin-top: clamp(3rem, 7vw, 5rem); border-top: 0; }
.hkfb-close .hkfb-lede { color: rgba(255, 255, 255, 0.82); }

/* ── .hkfb-pick — built by nav-v2.js, styled here ─────────────────────────
   Nothing below applies until the script has built the widget, because none
   of these classes exist in the shipped markup. The table it replaces is
   styled by .hkfb-t and needs no help. */
.hkfb-pick { margin: 1.75rem 0 0; }
.hkfb-pick__q {
  font-family: var(--sans); font-size: 0.6875rem; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--fg-muted); margin: 0 0 0.85rem;
}
.hkfb-pick__opts { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.5rem; }
/* Scoped to (0,3,1) on purpose. A bare .hkfb-pick__opt is (0,1,0) and the 45
   vendored theme stylesheets carry button rules well above that — the first
   version rendered every option in the selected state, because the theme's
   dark button background won and .is-on had nothing left to say. Specificity
   here is not decoration; it is the difference between a control that shows
   its state and one that does not. */
.hkfb-pick .hkfb-pick__opts button.hkfb-pick__opt {
  font-family: var(--sans); font-size: 0.875rem; line-height: 1.3;
  text-align: left; padding: 0.7rem 1.1rem; border-radius: 0; cursor: pointer;
  background: transparent; color: var(--fg);
  border: 1px solid var(--hairline); text-transform: none; letter-spacing: 0;
  box-shadow: none;
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
}
.hkfb-pick .hkfb-pick__opts button.hkfb-pick__opt:hover {
  border-color: var(--accent); color: var(--accent); background: transparent;
}
.hkfb-pick .hkfb-pick__opts button.hkfb-pick__opt.is-on {
  background: var(--fg-heading, #101018); color: #FFFFFF;
  border-color: var(--fg-heading, #101018);
}
.hkfb-pick__out { border-top: 1px solid var(--fg-heading, #101018); padding-top: 1.25rem; }
.hkfb-pick__dl { margin: 0 0 1.25rem; }
.hkfb-pick__dl dt {
  font-family: var(--sans); font-size: 0.6875rem; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--fg-muted); margin-top: 0.9rem;
}
.hkfb-pick__dl dd {
  font-family: var(--sans); font-size: 1rem; line-height: 1.55;
  color: var(--fg); margin: 0.2rem 0 0;
}
.hkfb-pick__go { margin-top: 0.5rem; }
.hkfb-pick__all { margin-top: 1.5rem; }
.hkfb-pick__all summary {
  font-family: var(--sans); font-size: 0.8125rem; letter-spacing: 0.06em;
  color: var(--fg-muted); cursor: pointer; padding: 0.5rem 0;
}
.hkfb-pick__all summary:hover { color: var(--accent); }

/* On the dark closing band the control has to invert or it disappears. */
.hkfb-close .hkfb-pick .hkfb-pick__opts button.hkfb-pick__opt {
  color: rgba(255,255,255,0.86); border-color: rgba(255,255,255,0.35); background: transparent;
}
.hkfb-close .hkfb-pick .hkfb-pick__opts button.hkfb-pick__opt.is-on {
  background: #FFFFFF; color: #101018; border-color: #FFFFFF;
}
.hkfb-close .hkfb-pick__out { border-top-color: rgba(255,255,255,0.4); }
.hkfb-close .hkfb-pick__dl dd { color: rgba(255,255,255,0.88); }

/* ═══════════════════════════════════════════════════════════════════════════
   DARK BANDS vs hkglobal.css — a specificity repair, not a restyle
   ═══════════════════════════════════════════════════════════════════════════

   The dark-band rules above are written as

       :is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close) .hkh-btn--solid

   and :is() takes the specificity of its MOST SPECIFIC argument, so that whole
   selector is (0,2,0). Three rules in the vendored hkglobal.css outrank it:

       .hk-content a.hkh-btn        (0,2,1)   color: #fff
       .hk-content strong, b        (0,1,1)   color: var(--fg-heading)
       .hk-content a:hover          (0,2,1)   color: var(--accent)

   The first is the expensive one. On a dark band the solid button is repainted
   white with ink-coloured text — then hkglobal puts the text back to #fff, so
   the button ships WHITE ON WHITE and the primary call to action is invisible.
   It is not a new bug: it is live today on every dark band that carries a
   solid button, which includes the homepage close and /reparasi-buku/'s mid
   CTA, and it is exactly why the button looked fine in markup and vanished in
   a screenshot.

   The band selector is therefore repeated. Doubling a compound raises
   specificity WITHOUT changing which elements match, which is what is wanted
   here — the match set is already correct, only the cascade was wrong. It is
   deliberate, not a typo. It also avoids scoping to .hk-content, which would
   have missed the homepage: that page's bands live under .hkh, not .hk-content.

   Do not "simplify" these back to a single :is(). That is the bug. */

:is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close):is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close) a.hkh-btn--solid {
  background: #FFFFFF; color: var(--ink, #101018); border-color: #FFFFFF;
}
:is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close):is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close) a.hkh-btn--solid:hover,
:is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close):is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close) a.hkh-btn--solid:focus-visible {
  background: var(--accent-light, #D8A87F); border-color: var(--accent-light, #D8A87F);
  color: var(--ink, #101018);
}
:is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close):is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close) a.hkh-btn--ghost {
  color: #FFFFFF; border-color: rgba(255, 255, 255, 0.45); background: transparent;
}
:is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close):is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close) a.hkh-btn--ghost:hover,
:is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close):is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close) a.hkh-btn--ghost:focus-visible {
  background: #FFFFFF; color: var(--ink, #101018); border-color: #FFFFFF;
}

/* Bold inside a dark band must follow its paragraph, not jump to the heading
   ink. inherit is right here: the paragraph already carries the correct
   light colour, and hard-coding a second white would drift from it. */
:is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close):is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close) :is(strong, b) {
  color: inherit;
}

/* A plain inline link on the band. --accent is 3.54:1 on this ground and
   --accent-deep is worse; --accent-light is the token that exists for it. */
:is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close):is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close) a:not(.hkh-btn):not(.hkfb-pick__go) {
  color: var(--accent-light, #D8A87F);
}
:is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close):is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close) a:not(.hkh-btn):not(.hkfb-pick__go):hover,
:is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close):is(.hkg-glow, .hkr-midcta, .hkh-close, .hkfb-close) a:not(.hkh-btn):not(.hkfb-pick__go):focus-visible {
  color: #FFFFFF;
}

/* ═══════════════════════════════════════════════════════════════════════
 * .hkwa — the floating WhatsApp button
 *
 * Markup: includes/wa-float.php. Copy and the off switch: config.php's
 * 'wa_float'. Two or more letters in the base by the namespace rule, so it
 * cannot collide with the bare .hkw already in this file.
 *
 * It declares no colour of its own: three component-local names mapped off
 * the global tokens. The green is --wa-green in tokens.css, flagged there as a
 * third-party brand colour and the one deliberate exception to the achromatic
 * interface — operator's instruction, 2026-08-11, for recognition.
 *
 * THE GLYPH AND LABEL ARE --ink, NOT WHITE, and that is not a style choice.
 * White on #25D366 is 1.98:1 and fails AA outright; ink on it is 9.54:1.
 * WhatsApp uses white on their app icon, where a glyph is not text. Here it
 * is a labelled button. Revert the foreground to white and the label becomes
 * unreadable for anyone with low vision, in sunlight, or on a dim screen.
 *
 * SQUARE, because border-radius: 0 is the measured button spec for this site.
 * 56px is the touch target — above the 48px floor, on a site where mobile is
 * 71% of clicks.
 * ═══════════════════════════════════════════════════════════════════════ */
.hkwa {
  --hkwa-bg:       var(--wa-green, #25D366);
  --hkwa-fg:       var(--ink, #101018);
  --hkwa-bg-hover: var(--wa-green-deep, #1DA851);

  position: fixed;
  right: 30px;
  bottom: 50px;
  /* Below the navigation's 90 so the mobile drawer always covers it, above
     everything in the document. */
  z-index: 80;

  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 56px;
  padding: 0 18px;
  box-sizing: border-box;

  background: var(--hkwa-bg);
  color: var(--hkwa-fg);
  border-radius: 0;
  text-decoration: none;

  font-family: var(--sans, Lato, sans-serif);
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 1px;
  text-transform: uppercase;

  box-shadow: 0 2px 14px rgba(16, 16, 24, .28);
  transition: background-color .18s ease, transform .18s ease;
}

.hkwa:hover,
.hkwa:focus-visible {
  background: var(--hkwa-bg-hover);
  color: var(--hkwa-fg);
  text-decoration: none;
  transform: translateY(-2px);
}

.hkwa:focus-visible {
  outline: 2px solid var(--hkwa-fg);
  outline-offset: 3px;
}

.hkwa__icon {
  display: inline-flex;
  flex: 0 0 auto;
}

.hkwa__icon svg {
  display: block;
  width: 24px;
  height: 24px;
}

/* The label is the affordance on a wide screen and dead weight on a narrow
   one, where the mark alone is unambiguous and the thumb needs the space. */
@media (max-width: 560px) {
  .hkwa {
    right: 16px;
    bottom: 16px;
    padding: 0;
    width: 56px;
    justify-content: center;
    gap: 0;
  }
  .hkwa__label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

/* jNews puts its back-to-top link at right:30px / bottom:50px — exactly where
   this button now sits. Stack them instead of letting them overlap. The
   compound selector outranks the vendored .jscroll-to-top (0,1,0) whatever the
   stylesheet order turns out to be. */
.jscroll-to-top.desktop {
  bottom: 118px;
}

@media (prefers-reduced-motion: reduce) {
  .hkwa { transition: none; }
  .hkwa:hover,
  .hkwa:focus-visible { transform: none; }
}

@media print {
  .hkwa { display: none; }
}

/* No dark-theme override. The green is a fixed brand colour and reads on both
   grounds; the earlier --ink ground needed one because it vanished on #000. */
