/* hk.assort-hair.com — the one-sheet (Ken-approved 2026-08-15).
   Ported VERBATIM from docs/reference/hk-serif-mock-2026-08-15.html's <style> block, then
   three additions, each fenced and commented below:
     1. adapters — the live tile/journal lanes emit their own markup; the layout adapts to
        them rather than the shared lanes being forked for one site;
     2. inner-page styles — the journal post page + the hub-side journal preview;
     3. print.
   Design system: docs/superpowers/specs/2026-08-15-hk-redesign-design.md §1 — Poppins +
   Cormorant Garamond (+ Noto Serif JP), white body, night frames, ONE accent (#e91e8a).
   NO Oswald, NO Sorts Mill Goudy, NO sideways vertical titles (all explicitly rejected). */

/* ======================= the approved mock, verbatim ======================= */
:root{--night:#0b0b0c;--silk:#f2f0ea;--dim:#8a8a8a;--paper:#ffffff;--ink:#000;--line:#eee;
  --nline:#2a2a28;--accent:#e91e8a;
  --serif:'Cormorant Garamond','Noto Serif JP',serif;--sans:'Poppins','Noto Serif JP',sans-serif}
*{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth}
body{background:var(--paper);color:var(--ink);font-family:var(--sans);font-weight:300;
  font-size:14.5px;line-height:1.85;-webkit-font-smoothing:antialiased}
a{color:inherit;text-decoration:none}
a:focus-visible,summary:focus-visible,button:focus-visible{outline:1px solid currentColor;outline-offset:4px}
img{max-width:100%;display:block}
.dsp{font-family:var(--sans);font-weight:400}
.jp{font-family:'Noto Serif JP',serif;font-weight:200}

/* ---------- the one-sheet: full-height night poster ---------- */
.poster{min-height:100svh;background:var(--night);color:var(--silk);display:flex;
  flex-direction:column;text-align:center}
.poster-top{flex:1;display:flex;align-items:center;justify-content:center;padding:24px}
.hlogo{width:min(112px,28vw);height:auto}
.film{position:relative;width:100%;aspect-ratio:2.35/1;overflow:hidden;background:#000}
.film iframe,.film img.fposter{position:absolute;top:50%;left:50%;width:100%;aspect-ratio:16/9;
  height:auto;transform:translate(-50%,-50%) scale(1.18);border:0;pointer-events:none;object-fit:cover}
@media(max-width:699px){.film iframe,.film img.fposter{transform:translate(-50%,-50%) scale(1.32)}}
.poster-foot{flex:1;padding:24px 24px 84px;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:22px}
.tagline{font-family:var(--serif);font-style:italic;font-size:21px;color:var(--silk)}
.credit{font-size:10px;letter-spacing:.34em;color:var(--dim);text-transform:uppercase}
.cta{font-family:var(--sans);font-weight:300;font-size:11.5px;letter-spacing:.3em;
  text-transform:uppercase;border:1px solid var(--nline);padding:16px 36px;
  transition:border-color .3s,color .3s}
.cta:hover{border-color:var(--accent);color:var(--accent)}

/* ---------- credits grammar ---------- */
main{max-width:700px;margin:0 auto;padding:0 24px}
section{padding:92px 0 0}
.ctitle{display:flex;align-items:center;gap:18px;justify-content:center;margin-bottom:38px}
.ctitle::before,.ctitle::after{content:'';height:1px;background:var(--line);flex:1}
.ctitle span{font-family:var(--sans);font-weight:300;font-size:10.5px;letter-spacing:.44em;
  text-transform:uppercase;color:var(--dim);white-space:nowrap;text-indent:.44em}
h2{font-family:var(--serif);font-weight:500;font-size:28px;letter-spacing:.01em;line-height:1.45;
  text-align:center;margin-bottom:22px}
p{color:#313131}
.fine{font-size:12.5px;color:var(--dim);line-height:1.8;margin-top:8px}
.row{display:flex;justify-content:space-between;gap:16px;align-items:baseline;
  padding:10px 0;border-bottom:1px solid var(--line);font-size:13.5px}
.row b{font-weight:300}
.row em{display:block;font-style:italic;font-size:12.5px;color:var(--dim)}
.row u{text-decoration:none;font-weight:300;font-variant-numeric:tabular-nums;white-space:nowrap}

/* story */
.story p{margin-bottom:15px;text-align:center;max-width:56ch;margin-left:auto;margin-right:auto}
.drop{font-style:italic}
.proof{margin-top:30px;text-align:center;font-size:12px;letter-spacing:.24em;
  text-transform:uppercase;color:var(--dim);line-height:2.3}

/* staff */
.people{display:grid;grid-template-columns:1fr 1fr;gap:34px 22px;text-align:center}
.person img{width:100%;aspect-ratio:4/5;object-fit:cover;filter:grayscale(24%) contrast(1.02);
  transition:filter .4s}
.person:hover img{filter:none}
/* Fix round 1 (Ken's LOCK, live-review 2026-08-19, all locations): a staff member with no photo
   on file renders this same-size tile instead — solid black, the site's own white lockup
   centered — never a borrowed photo or a generic silhouette. Same 4:5 footprint as `.person img`
   above; the nested lockup <img> needs its own higher-specificity rule (`.person
   .p-photo-blank img`, two classes) so it is NOT stretched to a cover-fill 4:5 box by the bare
   `.person img` rule above (one class + one type = lower specificity, would otherwise win by
   source order alone). */
.p-photo-blank{width:100%;aspect-ratio:4/5;background:#000;display:flex;align-items:center;
  justify-content:center}
.person .p-photo-blank img{width:60%;height:auto;aspect-ratio:auto;object-fit:contain;
  filter:none;display:block}
.p-name{font-family:var(--sans);font-weight:500;display:block;font-size:13.5px;
  letter-spacing:.14em;margin-top:6px;text-transform:uppercase}
.p-pos{display:block;font-family:var(--serif);font-style:italic;font-size:15px;
  color:var(--dim);margin:1px 0 3px}
.p-note{display:block;font-size:11px;line-height:1.5;color:var(--dim);margin:2px 0 1px}
.p-meta{display:block;font-size:11.5px;color:var(--dim)}
.p-ig{display:block;margin:12px auto 0;width:17px;height:17px;color:var(--dim)}
.person:hover .p-ig{color:var(--accent)}
.p-eng{display:flex;gap:3px;align-items:center;justify-content:space-between;
  border:1px solid var(--line);border-radius:999px;padding:5px 8px;margin:10px auto 4px;
  width:100%;transition:border-color .25s}
.person:hover .p-eng{border-color:#cfcfcf}
.p-eng b{font-size:8px;letter-spacing:.14em;color:var(--dim);font-weight:300;
  text-transform:uppercase;text-indent:.14em}
.p-dots{display:inline-flex;gap:3px;align-items:center}
/* Fix round 3 (Ken's live-review re-catch, 2026-08-19, MEASURED via a real headless-Chrome
   render, not CSS reasoning alone — see the task report for the pixel scan): round 1's grouped
   `.p-lvl-wrap` DID make the DOM gap between the dots box and the word an exact, equal 6px for
   every level word (confirmed again this round via getBoundingClientRect — identical for
   "advanced" and "intermediate"). The chip still LOOKED wrong for two separate, measured reasons:
   1. The empty (unfilled) dot's stroke was `#c5c5c5` — so pale that a strict-visibility pixel
      scan (luminance<200, roughly what a human eye registers as "there") found NO ink for it at
      all; the eye's true last visible mark for "advanced" ●●● is the 3rd (filled) dot, but for
      "intermediate" ●●○ it silently becomes the 2nd dot, one full dot+gap (~8px) short of where
      the group's real edge is — reading as an uneven, asymmetric rhythm even though the DOM box
      never moved. Darkened to var(--dim) below so the ring registers as real, visible ink at any
      normal zoom, restoring the 3rd position as the true last mark for every level word.
   2. "intermediate" (or a future long word like "conversational") genuinely didn't FIT — measured
      overflow: content ran 15.6px past the pill's own padding edge and 3.6px past its outer
      rounded border ("advanced" only ran 1.3px past padding — negligible, invisible). The word
      was visually crowding/overlapping the pill's own right edge, not the dots — reclaimed via
      tighter (not zero) padding and letter-spacing below, re-measured to confirm zero overflow. */
.p-eng i{width:5px;height:5px;border-radius:50%;border:1px solid var(--dim);flex:none}
.p-eng i.on{background:var(--ink);border-color:var(--ink)}
.p-lvl-wrap{display:flex;align-items:center;gap:6px}
.p-lvl{font-size:8.5px;letter-spacing:.04em;color:var(--ink)}

/* menu — thinner still (Ken round 3) */
.cat{border-bottom:1px solid var(--line)}
.cat summary{list-style:none;cursor:pointer;display:flex;align-items:baseline;gap:14px;
  justify-content:center;padding:18px 0;position:relative}
.cat summary::-webkit-details-marker{display:none}
.cs{font-family:var(--sans);font-weight:300;font-size:11.5px;letter-spacing:.34em;
  text-transform:uppercase;text-indent:.34em}
.cat .note{font-size:10.5px;letter-spacing:.04em;color:var(--dim)}
.cat .pm{position:absolute;right:2px;top:50%;width:11px;height:11px;margin-top:-6px}
.cat .pm::before,.cat .pm::after{content:'';position:absolute;background:var(--dim);
  top:5px;left:0;width:11px;height:1px;transition:transform .25s}
.cat .pm::after{transform:rotate(90deg)}
.cat[open] .pm::after{transform:rotate(0)}
.cat .row{border-bottom:none;padding:6px 0}
.mrow{font-size:13px}
.mrow b,.mrow u{font-weight:200}
.cat[open]{padding-bottom:16px}

/* journal */
/* wrap, never clip: with the restored 6-category vocabulary (2026-08-20) a 7-chip row
   overflows a phone viewport — flex's nowrap default CUT it at both edges (Ken's catch on the
   00337 staging). Rows wrap to extra centered lines; each chip stays one line (nowrap). */
.chips{display:flex;flex-wrap:wrap;gap:10px;justify-content:center;margin-bottom:30px}
.chip{font-size:10.5px;letter-spacing:.22em;text-transform:uppercase;border:1px solid var(--line);
  padding:7px 16px;color:var(--dim);white-space:nowrap}
.chip.on{border-color:var(--accent);color:var(--accent)}
.post{border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.post summary{list-style:none;cursor:pointer;display:grid;grid-template-columns:110px 1fr;
  gap:20px;align-items:center;padding:20px 0}
.post summary::-webkit-details-marker{display:none}
.thumb{aspect-ratio:1/1;background:var(--night);display:flex;align-items:center;
  justify-content:center;padding:14px}
.thumb img{width:68%;height:auto;opacity:.94}
.post-cat{font-size:10px;letter-spacing:.3em;text-transform:uppercase;color:var(--dim)}
.post-title{font-family:var(--sans);font-weight:400;display:block;font-size:15.5px;
  letter-spacing:.02em;margin:4px 0 2px}
.post-date{font-family:var(--serif);font-style:italic;font-size:14px;color:var(--dim)}
.post-body{padding:2px 0 24px;max-width:54ch;margin:0 auto}
.post-body p{margin-bottom:10px}

/* social */
.acct{display:flex;justify-content:space-between;align-items:baseline;font-size:13px;
  letter-spacing:.06em;margin:28px 0 12px}
.acct .dsp{letter-spacing:.22em;text-transform:uppercase;font-size:11px;font-weight:300}
.acct span:last-child{font-size:11.5px;color:var(--dim)}
.strip{display:flex;gap:10px;overflow-x:auto;scroll-snap-type:x mandatory;
  padding-bottom:6px;scrollbar-width:none}
.strip::-webkit-scrollbar{display:none}
.ph{flex:0 0 31%;scroll-snap-align:start;position:relative}
.ph img{aspect-ratio:1/1;object-fit:cover}
.ph span{position:absolute;left:0;bottom:0;right:0;font-size:9.5px;color:#fff;
  background:linear-gradient(transparent,rgba(0,0,0,.55));padding:14px 7px 5px;letter-spacing:.08em}
.strip.wide .ph{flex:0 0 58%}
.strip.wide .ph img{aspect-ratio:16/9}
.strip .ph.tall{flex:0 0 31%}
.strip .ph.tall img{aspect-ratio:9/16}

/* reviews — Google review cards, real data */
.gsum{display:flex;align-items:center;justify-content:center;gap:12px;margin-bottom:30px}
.gsum .gg{width:26px;height:26px}
.gsum b{font-family:var(--sans);font-weight:400;font-size:24px}
.gsum .gstars{margin:0}
.gsum a{font-size:11.5px;color:var(--dim);border-bottom:1px solid var(--line)}
.gsum a:hover{color:var(--accent);border-color:var(--accent)}
.gstars{color:#fbbc04;font-size:14px;letter-spacing:3px;margin:8px 0 6px}
.star-wrap{position:relative;display:inline-block;color:#e0e0e0}
.star-fill{position:absolute;left:0;top:0;overflow:hidden;color:#fbbc04;white-space:nowrap}
.grev{max-width:58ch;margin:0 auto 18px;border:1px solid var(--line);padding:18px 20px 16px;
  text-align:left}
.grev p{font-size:13px;line-height:1.75;color:#313131}
.grev-head{display:flex;align-items:center;gap:12px}
.gav{width:34px;height:34px;border-radius:50%;color:#fff;display:flex;align-items:center;
  justify-content:center;font-size:14px;font-weight:400;flex:none}
.grev-who{flex:1;line-height:1.35}
.grev-who b{display:block;font-weight:400;font-size:13px}
.grev-who i{font-style:normal;font-size:11px;color:var(--dim)}
.grev .gg{width:18px;height:18px;flex:none}

/* salons of the world */
.locs-grid{display:grid;grid-template-columns:1fr 1fr;gap:30px 12px;text-align:center}
.loc{display:flex;flex-direction:column;gap:2px}
.loc .city{font-family:var(--serif);font-weight:500;font-size:23px;letter-spacing:.02em;
  transition:color .25s}
a.loc .city::after{content:' \2197';font-size:12px;color:var(--dim);vertical-align:6px}
.loc .ctry{font-size:9px;letter-spacing:.32em;text-transform:uppercase;color:var(--dim);
  text-indent:.32em}
.loc:hover .city{color:var(--accent)}
.ynh{font-family:var(--serif);font-style:italic;font-size:12px;color:var(--accent)}
.locs .fine{text-align:center;margin-top:30px}

/* salon + cancellation */
/* The salon name leads the facts block (Ken 2026-08-18) — tracked caps so the mixed-case
   config names (ASSORT NEW YORK / Assort Vancouver) render uniformly. */
.sname{font-family:var(--sans);font-weight:300;font-size:13px;letter-spacing:.3em;
  text-transform:uppercase;text-indent:.3em;text-align:center;margin:0 0 22px}
.map{filter:grayscale(1) sepia(.06);margin:28px 0 0}
.map iframe{width:100%;height:300px;border:0;display:block}
.pol p{max-width:54ch;margin:0 auto 14px;text-align:center}
.pol .fine{text-align:center;max-width:54ch;margin:22px auto 0}
.pol a{border-bottom:1px solid var(--line)}
.pol a:hover{color:var(--accent);border-color:var(--accent)}

/* credits roll */
.end{background:var(--night);color:var(--dim);margin-top:100px;padding:78px 24px 128px;text-align:center}
.end .flogo{width:min(102px,26vw);height:auto;margin:0 auto 22px}
/* Footer SNS icon row (Ken's ruling 2026-08-20: country footers carry the icons like MAIN's —
   local IG/FB doors + the global TT/YT/X/Pinterest). MAIN's own footer posture: dim ink
   warming to white on hover (the .legal grammar, not accent — this is the night band). */
.end .fsoc{display:flex;justify-content:center;align-items:center;flex-wrap:wrap;gap:14px 26px;
  margin:4px 0 24px;color:var(--dim)}
.end .fsoc a{display:block;color:inherit;transition:color .25s}
.end .fsoc a:hover{color:#fff}
.fsoc-ic{width:19px;height:19px;display:block}
.end p{font-size:12px;line-height:2.1;letter-spacing:.04em;color:#fff;font-weight:300}
.end .legal{margin-top:16px;font-size:10.5px;color:var(--dim)}
.end .legal a{color:var(--dim);border-bottom:1px solid var(--nline);padding-bottom:1px}
.end .legal a:hover{color:#fff}
.end .legal span{margin:0 8px}

/* language toggle — the mock swapped a dictionary client-side, so its toggle was a <button>.
   The real site serves two SERVER-RENDERED pages, so the toggle is two links: same look,
   `.on` marks the page you are on. */
.lng{position:fixed;top:20px;left:20px;z-index:12;display:flex;gap:10px;
  mix-blend-mode:difference}
.lng a{border:0;background:none;cursor:pointer;color:#fff;font-family:var(--sans);
  font-weight:300;font-size:10px;letter-spacing:.22em;opacity:.45;padding:6px 2px;
  transition:opacity .25s}
.lng a.on{opacity:1;border-bottom:1px solid #fff}

/* hamburger + nav — fullscreen on phones, right drawer on desktop */
.nav-btn{position:fixed;top:20px;right:20px;z-index:12;width:44px;height:44px;border:0;
  background:none;cursor:pointer;color:#fff;mix-blend-mode:difference;padding:12px 10px;
  display:flex;flex-direction:column;justify-content:center;gap:7px}
.nav-btn span{display:block;height:1px;background:currentColor;transition:transform .3s,opacity .3s}
.nav-open .nav-btn span:first-child{transform:translateY(4px) rotate(45deg)}
.nav-open .nav-btn span:last-child{transform:translateY(-4px) rotate(-45deg)}
.nav{position:fixed;inset:0;background:var(--night);z-index:11;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:24px;opacity:0;visibility:hidden;
  transition:opacity .35s,visibility .35s}
.nav-open .nav{opacity:1;visibility:visible}
.nav a{font-family:var(--sans);font-weight:200;font-size:13px;letter-spacing:.34em;
  text-transform:uppercase;color:var(--silk);text-indent:.34em;transition:color .25s}
.nav a:hover{color:var(--accent)}
.nav .nav-book{color:var(--accent)}
@media(min-width:700px){
  .nav{left:auto;width:400px;border-left:1px solid var(--nline);
    align-items:flex-start;padding-left:64px;gap:20px}
  .nav a{text-indent:0}
}
/* `html{scroll-behavior:smooth}` above + a nav that is ALL in-page anchors = a full-page
   glide on every nav tap; carried over from the pre-rewrite stylesheet, which the mock (a
   throwaway with no such guard) had no equivalent of. */
@media(prefers-reduced-motion:reduce){.nav,.nav-btn span,.lng a{transition:none}html{scroll-behavior:auto}}

/* sticky book bar */
.bar{position:fixed;left:0;right:0;bottom:0;background:rgba(11,11,12,.9);
  backdrop-filter:blur(10px);border-top:1px solid var(--nline);z-index:9}
.bar a{display:block;text-align:center;padding:15px 0;color:var(--silk);
  font-family:var(--sans);font-weight:300;font-size:11px;letter-spacing:.32em;text-transform:uppercase}

@media(min-width:700px){
  .people{grid-template-columns:repeat(4,1fr)}
  .ph{flex-basis:23%}
  .strip.wide .ph{flex-basis:40%}
  .strip .ph.tall{flex-basis:18%}
  .locs-grid{grid-template-columns:repeat(4,1fr)}
}

/* ================== 1. adapters: live lanes → this layout ================== */

/* The social strips are filled by the EXISTING tile lanes (lib/van-ig-feed, lib/site-video-tiles),
   whose markup is `<a class="tile"><img>[<span class="tile-stats">]` and which feed several
   sites at once. Those lanes are never forked for one site's design, so the strip adapts to
   them: the geometry below mirrors the mock's `.ph` rules exactly (square IG, 16:9 YouTube,
   9:16 TikTok — `.strip.tall` replaces the mock's per-tile `.ph.tall`). */
.strip .tile{flex:0 0 31%;scroll-snap-align:start;position:relative;display:block}
.strip .tile img{width:100%;aspect-ratio:1/1;object-fit:cover}
.strip .tile .tile-stats{position:absolute;left:0;bottom:0;right:0;font-size:9.5px;color:#fff;
  background:linear-gradient(transparent,rgba(0,0,0,.55));padding:14px 7px 5px;letter-spacing:.08em}
.strip.wide .tile{flex:0 0 58%}
.strip.wide .tile img{aspect-ratio:16/9}
.strip.tall .tile{flex:0 0 31%}
.strip.tall .tile img{aspect-ratio:9/16}
.strip:empty{display:none}        /* a lane that failed open leaves no ghost gap */
.acct span:last-child:empty{display:none}

/* Task 5 (UK site migration plan, Ken's queued fleet rider, 2026-08-18 #12: "ALL country sites
   get the B/W social icons at their social sections"). The `.acct` row's platform LABEL now
   carries a monochrome SVG mark (lib/social-icons.js — the same shared source MAIN's own social
   rows draw from) ahead of the text; `.acct .dsp` gains a small flex layout to align icon + text
   (new properties only — the mock's own letter-spacing/size/weight rule above is untouched), and
   `.p-soc-ic` sizes/colors the mark. Own class, scoped to this sheet: MAIN's identically-drawn
   "soc-ic" class lives in views/site-main.html's own <style> block, a separate stylesheet. */
.acct .dsp{display:flex;align-items:center;gap:8px}
.p-soc-ic{width:14px;height:14px;flex:none;color:var(--ink)}

/* Journal cards are LINKS to each post's own URL (the mock opened bodies in place; every real
   post is its own indexed document — spec §2.5/§4), so the mock's `.post summary` grid moves
   onto the anchor and its double hairline collapses to one rule per card. */
a.post{display:grid;grid-template-columns:110px 1fr;gap:20px;align-items:center;padding:20px 0;
  border-top:0;border-bottom:1px solid var(--line)}
a.post:first-of-type{border-top:1px solid var(--line)}
a.post .post-title{transition:color .25s}
a.post:hover .post-title{color:var(--accent)}
/* a post WITH an image fills the thumb with it; the image-less card keeps the mock's
   white-logo-on-night treatment above */
.thumb.pic{padding:0}
.thumb.pic img{width:100%;height:100%;object-fit:cover;opacity:1}

/* Uniform 4:5 portraits (spec §2.3) — `1fr` is `minmax(auto,1fr)`, so the widest card's
   min-content (a long handle, a wide level word) steals width from its neighbours and the
   photos render at four different sizes. Measured in headless Chrome: 146/160/146/140px wide
   before this rule, 4 × 148px after. */
.people{grid-template-columns:repeat(2,minmax(0,1fr))}
@media(min-width:700px){
  .people{grid-template-columns:repeat(4,minmax(0,1fr))}
  /* Fix round 1 (Ken's live-review catch, 2026-08-19: "when there is 2 rows for the name
     (example kikumi shirakawa) i dont like how the alignment on the desktop version is ... i
     want them nice and neat"). `.p-name` has no fixed height, so a name that wraps to a second
     line pushes .p-pos/.p-eng/.p-meta down inside THAT card only — CSS Grid's default row-stretch
     equalises each `.person` cell's total height, but content inside the shorter-named cards
     stays top-anchored, so their position/chip/handle rows sit HIGHER than the wrapped card's in
     the same row. Reserving a fixed two-line box (2 × the inherited 1.85 line-height = 3.7em)
     keeps every card's rows starting at the same y whether its real name wraps or not — desktop
     (4-up grid) only, checked at 1280/700/390: mobile's 2-up grid never showed the same seam. */
  .p-name{min-height:3.7em}
}

/* menu item subtitles (GLOBAL MILBON / K-18 / TOKIO) — carried from the live price list */
.msub{font-family:var(--sans);font-weight:400;font-size:9.5px;letter-spacing:.28em;
  text-transform:uppercase;color:var(--dim);text-align:center;margin:14px 0 2px;text-indent:.28em}

@media(min-width:700px){
  .strip .tile{flex-basis:23%}
  .strip.wide .tile{flex-basis:40%}
  .strip.tall .tile{flex-basis:18%}
}

/* ============ 2. inner pages: journal post + hub-side preview ============ */
.pagewrap{max-width:700px;margin:0 auto;padding:96px 24px 40px}
.crumb{font-size:10.5px;letter-spacing:.34em;text-transform:uppercase;color:var(--dim);
  text-align:center;margin-bottom:30px;text-indent:.34em}
/* Round 3 ①: the crumb now carries the post's own category ("ASSORT MELBOURNE — DESIGN
   COLOR"), longer than the old static NEWS. On a phone the nowrap span outgrows the flex
   row (hairlines + 18px gaps), so narrow viewports tighten the tracking to the .chip scale —
   one line survives with the hairlines intact — and keep wrap as the last resort for
   viewports narrower still. Desktop is untouched. */
@media (max-width:430px){
  .crumb span{letter-spacing:.22em;text-indent:.22em;white-space:normal}
}
.crumb a{border-bottom:1px solid var(--line);padding-bottom:2px}
.crumb a:hover{color:var(--accent);border-color:var(--accent)}
.news-post{text-align:center}
.news-post .news-cat{font-size:10px;letter-spacing:.3em;text-transform:uppercase;color:var(--dim)}
.news-post h1{font-family:var(--serif);font-weight:500;font-size:30px;line-height:1.35;
  letter-spacing:.01em;margin:10px 0 6px}
.news-post time{font-family:var(--serif);font-style:italic;font-size:14px;color:var(--dim)}
.news-body{margin:34px auto 0;max-width:54ch;text-align:left}
.news-body p{margin-bottom:14px}
.news-body h2{font-family:var(--serif);font-weight:500;font-size:22px;text-align:left;
  margin:28px 0 8px}
.news-body img,.news-body video{width:100%;height:auto;margin:20px 0}
/* The default closing-CTA block (lib/blocks.js's `cta` block type, review catch 2026-08-19: the
   classes rendered with zero backing CSS, so the "button" was visually plain paragraph text).
   Reuses the EXACT .cta button treatment verbatim — bordered box, uppercase, .3em letter-spacing,
   thin sans weight, accent-on-hover — the same grammar .team-apply and .notify-form button
   already copy for THEIR own buttons (see their own comments, section 4/5 below), so a booking
   button inside a journal post reads as this site's own button, not a bolted-on link. */
.news-body .post-cta{text-align:center;margin:32px 0}
.news-body .post-cta-link{display:inline-block;font-family:var(--sans);font-weight:300;
  font-size:11.5px;letter-spacing:.3em;text-transform:uppercase;border:1px solid var(--nline);
  padding:16px 36px;transition:border-color .3s,color .3s}
.news-body .post-cta-link:hover{border-color:var(--accent);color:var(--accent)}
/* the hub-side preview banner (lib/site-preview.js) — never on the public page */
.pv-note{border:1px solid var(--line);padding:14px 16px;font-size:12.5px;color:var(--dim);
  text-align:left;margin-bottom:26px}

/* ============================== 3. print ============================== */
@media print{
  .bar,.nav,.nav-btn,.lng{display:none}
  .poster{min-height:auto}
}

/* ==================== 4. pre-opening (CA re-skin plan, Task 5) ====================
   CA opens December 2026 with no staff and no cancellation policy on record yet — Ken's rule:
   hide/repurpose empty team/reviews/journal sections rather than render an empty shell.
   lib/site-builder.js's buildTeamGrid/buildPolicy pre-opening branches emit these seven classes;
   HK's cfg never reaches either branch, so none of this is reachable on hk.assort-hair.com.
   NEW selectors only — nothing above this fence is edited, HK's render does not move a pixel.
   Reuses the design system as-is: serif italic for the identity line (.tagline/.p-pos/.post-date/
   .ynh idiom), the same 54ch centered paragraph measure the story/policy sections use, and the
   exact .cta button treatment (bordered box, uppercase, accent-on-hover) for the recruiting
   card, so a pre-opening section reads as the same site, not a bolted-on placeholder. */
.people-soon{text-align:center;max-width:54ch;margin:0 auto}
.team-soon-title{font-family:var(--serif);font-style:italic;font-weight:500;font-size:20px;
  letter-spacing:.01em;margin-bottom:10px}
.team-soon-body{font-size:13.5px;color:#313131;margin-bottom:26px}
.team-apply{display:inline-block;font-family:var(--sans);font-weight:300;font-size:11.5px;
  letter-spacing:.3em;text-transform:uppercase;border:1px solid var(--line);padding:16px 30px;
  transition:border-color .3s,color .3s}
.team-apply:hover{border-color:var(--accent);color:var(--accent)}

.preopen{text-align:center;max-width:54ch;margin:0 auto}
.preopen-title{font-family:var(--serif);font-style:italic;font-weight:500;font-size:20px;
  letter-spacing:.01em;margin-bottom:10px}
.preopen-body{font-size:13.5px;color:#313131;margin-bottom:22px}

/* ==================== 5. notify form (CA re-skin plan, Task 7) ====================
   routes/vancouver.js fills lib/site-builder.js's {{NOTIFY_FORM}} slot (inside .preopen above)
   with the real form ported from the deleted views/vancouver.html. Same underline-input idiom
   the rest of this design system already uses for compact fields, and the exact .cta button
   treatment for the submit button, so the form reads as this site, not a bolted-on widget.
   NEW selectors only — HK never renders this markup (cfg.notify is unset), so its render does
   not move a pixel. */
.notify-form{display:flex;gap:10px;flex-wrap:wrap;justify-content:center;margin-top:2px}
.notify-form input{flex:1;min-width:220px;border:0;border-bottom:1px solid var(--line);
  padding:10px 2px;font-family:var(--sans);font-weight:300;font-size:13.5px;background:none;
  color:var(--ink);text-align:center}
.notify-form input:focus{outline:none;border-color:var(--ink)}
.notify-form button{font-family:var(--sans);font-weight:300;font-size:11px;letter-spacing:.3em;
  text-transform:uppercase;border:1px solid var(--nline);background:none;color:var(--ink);
  padding:12px 26px;cursor:pointer;transition:border-color .3s,color .3s}
.notify-form button:hover{border-color:var(--accent);color:var(--accent)}
.notify-form button:disabled{opacity:.5;cursor:default}
/* Ken's 2026-08-17 order (staged compare): ONE wordmark size for every site — both logo assets
   are now tight crops (HK PNG 700x250; canada PNG cut from the padded square SVG canvas, which
   was inflating CA's header/footer height), so the base rule carries the approved size. */

/* ============ 6. two-salon sites (NL site migration plan, Task 2) ============
   NL is the first country on this engine with TWO salons (Assort Amsterdam + Fairfax); JP is
   next. lib/site-builder.js emits these classes ONLY when the config carries the optional
   `cfg.salon_locations` array / a per-staff `group` — no current site (hk/ca/us/uk/au/main)
   does, so nothing here is reachable on any live page today and no existing selector above is
   edited. NEW selectors only; the HK golden fixtures prove the render does not move.
   Reuses the design system as-is: .sname is the existing salon-name treatment (one per block
   now instead of one per page), the BOOK button copies the exact .team-apply/.cta treatment,
   and the group label is the .p-pos/.tagline serif-italic identity idiom. */
.sfacts-multi .sloc + .sloc{margin-top:70px;padding-top:64px;border-top:1px solid var(--line)}
.sloc-logo{display:block;width:min(120px,30vw);height:auto;margin:0 auto 18px}
.sloc-book{text-align:center;margin-top:30px}
.sloc-book-link{display:inline-block;font-family:var(--sans);font-weight:300;font-size:11.5px;
  letter-spacing:.3em;text-transform:uppercase;border:1px solid var(--line);padding:16px 30px;
  transition:border-color .3s,color .3s}
.sloc-book-link:hover{border-color:var(--accent);color:var(--accent)}
/* The label sits ABOVE its own .people grid; the first one carries no top margin because the
   section's .ctitle already opens the block. */
.team-group-label{font-family:var(--serif);font-style:italic;font-size:20px;color:var(--dim);
  text-align:center;margin:48px 0 20px}
.team-group-label:first-child{margin-top:0}

/* ============ 7. staff cards — reserved glyph row + multi-language badges ============
   Two Ken rulings from the same live site review (2026-08-19/20). NEW selectors only: nothing
   above is edited, so every card that already looked right renders byte-identically (the HK
   golden fixtures are the fleet-wide proof).

   .p-ig-gap — the FLEET-WIDE alignment defect Ken screenshotted: a card with no Instagram used
   to emit nothing in the glyph slot, so its name/role/pill rows sat one glyph-row higher than
   its neighbours' (Paris Nguyen on the NL site). lib/site-builder.js now always fills the slot;
   this rule gives the invisible filler the EXACT `.p-ig` box above (display/margin/width/height
   copied deliberately, and pinned against it in lib/__tests__/site-css-chip-spacing.test.js) so
   the reserved space is identical, never merely similar.

   .p-eng + .p-eng — a staff member can now carry several languages, one pill per language,
   stacked. A lone pill's own `margin:10px auto 4px` would leave a collapsed 10px between two
   pills, reading as separate chips; 4px collapses them into one badge group while keeping the
   pill's own 10px lead-in below the name and its 4px exit above the handle. */
.p-ig-gap{display:block;margin:12px auto 0;width:17px;height:17px}
.p-eng + .p-eng{margin-top:4px}

/* ============ 8. journal: the SEE ALL door + the /journal/ archive page ============
   Ken's live ruling, 2026-08-20 (verbatim): "too many journals (it should only show recent 5).
   for all sites. and if they click 'see all' then there should be a dedicated journal page that
   is nice and neat that meets our design standards. this is for all locations."
   NEW selectors only — nothing above this fence is edited, so every existing page renders
   byte-identically (the HK golden fixtures are the fleet-wide proof; their own diff for this
   change is the version bump plus the new SEE ALL door, nothing else).

   Reuses the design system as-is rather than inventing an archive look: the door copies the
   exact `.cta`/`.team-apply`/`.sloc-book-link` button treatment (bordered box, uppercase, .3em
   letter-spacing, thin sans, accent-on-hover); the archive's cards reuse the SAME `.thumb` /
   `.post-cat` / `.post-title` / `.post-date` vocabulary the home journal cards already draw
   (lib/site-builder.js shares one thumb + meta builder between the two surfaces), so the page
   reads as the journal it belongs to, not a second design; the page title is the site's serif
   display face at the `.news-post h1` size. */
.jmore{text-align:center;margin-top:34px}
.jmore-link{display:inline-block;font-family:var(--sans);font-weight:300;font-size:11.5px;
  letter-spacing:.3em;text-transform:uppercase;border:1px solid var(--line);padding:15px 34px;
  transition:border-color .3s,color .3s}
.jmore-link:hover{border-color:var(--accent);color:var(--accent)}

/* The archive needs a wider measure than the 700px reading column a journal POST wants — the
   grid is the content here, not prose. `.pagewrap.wide` is set by fillPageTemplate's own
   `wrapMod` slot (views/site-page.html), which is EMPTY for every other page. */
.pagewrap.wide{max-width:1080px}
.jindex-title{font-family:var(--serif);font-weight:500;font-size:30px;line-height:1.35;
  letter-spacing:.01em;text-align:center;margin:0 0 44px}
.jgrid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:44px 30px}
@media(min-width:700px){.jgrid{grid-template-columns:repeat(3,minmax(0,1fr));gap:56px 34px}}
/* The card is a column (thumb over text), unlike the home list's 110px-thumb row. `.thumb`'s
   own 1/1 aspect ratio + night background carry over untouched, so an image-less post still
   shows the salon's white logo on night exactly as it does on the home page. */
.jcard{display:block}
.jcard .thumb{width:100%}
/* An image-less card's white-logo thumb: .thumb img's 68% of the archive's ~340px tile would
   paint the logo ~3x the size the home list shows it — cap it back to the home's visual scale. */
.jcard .thumb:not(.pic) img{width:33%}
.jcard-meta{display:block;margin-top:14px}
.jcard .post-title{transition:color .25s}
.jcard:hover .post-title{color:var(--accent)}

/* The archive masthead + working category filter (Ken's staged-preview rulings, 2026-08-20:
   "the header logo is gone along with the languages." / "where is the filter for categories
   etc?"). Still section 8, still NEW selectors only.
   .jmast is the night band between the nav and the white reading column — it exists to host the
   home's WHITE assets (the journal logo + the .lng language group) on the archive's white-paper
   page. .jmast .lng un-fixes the home's position:fixed toggle so it pins to the band, not the
   viewport. The band replaces most of .pagewrap's 96px top gap.
   Logo scale (Ken's 2nd preview round, 2026-08-20: "the header logo is too big.") — EXACTLY the
   home hero's .hlogo width rule (line 30 above); the old min(46vw,200px) read ~40% of a phone
   screen. The band's padding tightens with it (was 64/44) but keeps the .lng row clear of the
   logo at 320px. */
.jmast{background:var(--night);padding:56px 24px 36px;text-align:center;position:relative}
.jmast-logo{width:min(112px,28vw);height:auto;display:inline-block}
.jmast .lng{position:absolute;top:20px;left:20px}
.jmast+ .pagewrap{padding-top:56px}
.jchips{margin-bottom:38px}
/* The filter chips are ANCHORS now (Ken's 2nd preview round, 2026-08-20 — the client-side
   filter script is gone; each chip is a real server-side link: All → the archive base, a
   category → ?cat= on it). `.chip`/`.chip.on` still own the look; a link chip only adds the
   hover the design system already gives every bordered micro-label (.cta/.jmore-link) — accent
   on hover/active ONLY, per Ken's "keep the clean look, dont make it too 'pop'". */
.jchips .chip{transition:border-color .3s,color .3s}
.jchips .chip:hover{border-color:var(--accent);color:var(--accent)}

/* ============ 9. journal pagination + post navigation (Ken's 2nd preview round, 2026-08-20:
   "there should be a 'next' etc like any normal blog page." / "that page also has to be able to
   'return' … and also on the bottom, should show recommendations for similar posts etc." —
   tempered by his mid-build ruling: "keep the 'journal' clean look. dont make it too 'pop'").
   NEW selectors only. Everything here stays QUIET and editorial: thin sans, wide letter-spacing,
   hairline borders, no filled buttons — the accent appears only where the system already uses
   it (.chip.on's current state, hover). */

/* The numbered page bar under the archive grid. Current page = the .on accent (the .chip.on
   grammar); other numbers and PREV/NEXT are thin dim sans that warm to accent on hover. */
.jpage{display:flex;justify-content:center;align-items:baseline;flex-wrap:wrap;gap:8px 18px;
  margin-top:64px;font-family:var(--sans);font-weight:300;font-size:10.5px;
  letter-spacing:.3em;text-transform:uppercase;color:var(--dim)}
.jpage a{transition:color .25s}
.jpage a:hover{color:var(--accent)}
.jpage .jpage-n.on{color:var(--accent)}
.jpage .jpage-gap{letter-spacing:0}

/* The post page's return door — round 3 (Ken 2026-08-20: "more like a 'back' or 'return'
   button") + his flip-time amendment ("center the '←journal' then flip"): the .chip grammar
   verbatim (hairline border, 7px 16px, .22em — pixel-equal to the archive's own buttons),
   CENTERED above the article. display:table shrink-wraps the button so auto margins center
   it without any wrapper markup. */
.jback{display:table;margin:0 auto 34px;font-size:10.5px;letter-spacing:.22em;
  text-transform:uppercase;border:1px solid var(--line);padding:7px 16px;color:var(--dim);
  transition:color .25s,border-color .25s}
.jback:hover{color:var(--accent);border-color:var(--accent)}

/* The share row closing the article (Ken's round-3 ask, 2026-08-20, + round 4 same day:
   "simple black and white icons? for the shairng?") — hairline top rail, monochrome
   currentColor marks from lib/social-icons.js, dim ink warming to accent on hover; the SHARE
   lead-in keeps the quiet 9px small-caps. .jshare-copy is a real <button> stripped to bare
   ink (copy-link and the native share-sheet door both wear it) — no filled buttons, ever.
   The .jshare-open native door ships [hidden]; the post's inline script unhides it only when
   navigator.share exists (phones — the OS sheet is where Instagram lives, since IG has no
   web share URL). */
.jshare{display:flex;justify-content:center;align-items:center;flex-wrap:wrap;gap:10px 22px;
  margin-top:48px;padding-top:22px;border-top:1px solid var(--line);
  font-family:var(--sans);font-weight:300;font-size:9px;letter-spacing:.3em;
  text-transform:uppercase;color:var(--dim)}
.jshare a{display:block;color:inherit;transition:color .25s}
.jshare a:hover{color:var(--accent)}
.jshare-ic{width:17px;height:17px;display:block}
.jshare-copy{background:none;border:0;padding:0;cursor:pointer;color:inherit;line-height:0;
  transition:color .25s}
.jshare-copy:hover{color:var(--accent)}
/* .jshare-ic's display:block would beat the UA's [hidden]{display:none} (author rules always
   win over UA rules) — restate hidden explicitly so the copy button's check mark and the
   native door stay invisible until their scripts say otherwise. */
.jshare [hidden]{display:none}

/* The stylist byline under the post's date line (recut 5, Ken's Y — post pages only, cards
   stay clean). The .crumb vocabulary verbatim: small caps, dim, thin sans, quiet; accent only
   on hover, like every other micro-label door in this system. The text is already uppercased
   by the builder — the text-transform here just keeps a future mixed-case value in grammar. */
.jby{display:block;text-align:center;font-size:10.5px;letter-spacing:.34em;
  text-transform:uppercase;color:var(--dim);text-indent:.34em;margin-top:14px;
  transition:color .25s}
.jby:hover{color:var(--accent)}

/* Related posts under the article — the heading reuses .ctitle's hairline treatment verbatim
   (the class rides alongside it in the markup); only the section lead-in is new. The grid is
   the archive's own .jgrid/.jcard vocabulary, up to 3 cards. */
.jrel-h{margin-top:92px}

/* The newer/older neighbor row — two cells over one hairline, labels in small caps, titles in
   thin sans. The right (older) cell right-aligns so the pair reads as one quiet rail. */
.jnav{display:flex;justify-content:space-between;gap:24px;margin-top:56px;padding-top:24px;
  border-top:1px solid var(--line)}
.jnav-cell{flex:1;min-width:0}
.jnav-cell:last-child{text-align:right}
.jnav-lab{display:block;font-size:9px;letter-spacing:.3em;text-transform:uppercase;
  color:var(--dim);margin-bottom:4px}
.jnav-t{display:block;font-family:var(--sans);font-weight:300;font-size:13px;
  letter-spacing:.02em;transition:color .25s}
a.jnav-cell:hover .jnav-t{color:var(--accent)}
