/*
 * Clever Dog site kit — the finished pieces every plain site carries (BATCH 24oct SITE-KIT-1).
 * Lifted from Westside Ceilings' served site.css (rounds 1–6, 19–23 Oct 2026), with every colour of that site taken
 * out: a glow takes the button's own colour (motion.js reads it), shadows are neutral, the rest inherits the site.
 * Linked on every page AFTER site.css. The author's site.css is never edited by this file and never needs to be.
 *
 * The rules of the kit (WESTSIDE-INTO-THE-ENGINE D1):
 *   · hover effects only under (hover:hover), so a phone never gets a sticky hover;
 *   · only transform, opacity and box-shadow move — nothing changes size, so nothing on the page shifts;
 *   · everything here is off under prefers-reduced-motion (the last block).
 */
:root{--kit-ease:cubic-bezier(.22,.61,.36,1);--kit-shadow:0 18px 40px rgba(0,0,0,.16)}

/* ── C1 (SITE-KIT-2) · a <picture> around a photo is laid out as if it were not there, so a layout written for <img>
   holds: the <img> inside is the box. ── */
picture{display:contents}

/* ── I2/M0b (SITE-KIT-2) · the engine's own pages: the 404 and the privacy policy, in a reading column. ── */
/* BATCH 9nov — the band itself is named by the kit, so a class written on a page always has a rule (Rick's rule 6). */
.kit-policy{display:block}
.kit-policy__inner{max-width:46rem;margin:0 auto;padding:48px 20px}
.kit-policy__inner h2{margin-top:1.6em}

/* ── D1 · scroll reveal: the children of [data-reveal] fade and rise in (motion.js). Hidden only once the script runs. ── */
.kit-reveal-on .kit-reveal{opacity:0;transform:translateY(16px);transition:opacity .5s var(--kit-ease),transform .5s var(--kit-ease)}
.kit-reveal-on .kit-reveal.is-in{opacity:1;transform:none}
@media print{.kit-reveal-on .kit-reveal{opacity:1!important;transform:none!important}}

/* ── D1 · photos beside the words ([data-photo]): settle in from a slight zoom as they arrive, ease closer under the pointer ── */
:where([data-photo]){overflow:hidden}
[data-photo] img{transition:transform 1.1s var(--kit-ease)}
.kit-reveal-on .kit-reveal:not(.is-in)[data-photo] img,.kit-reveal-on .kit-reveal:not(.is-in) [data-photo] img{transform:scale(1.06)}

/* ── D1 · tiles, reviews and the gallery lift a little under the pointer ── */
[data-lift]{transition:transform .3s var(--kit-ease),box-shadow .3s var(--kit-ease)}
:where(.gallery-grid a){display:block;overflow:hidden;transition:transform .35s var(--kit-ease),box-shadow .35s var(--kit-ease)}
.gallery-grid img{transition:transform .9s var(--kit-ease)}
.gallery-grid a:focus-visible{outline:3px solid currentColor;outline-offset:4px}
@media (hover:hover){
  [data-photo]:hover img{transform:scale(1.04)}
  [data-lift]:hover{transform:translateY(-4px);box-shadow:var(--kit-shadow)}
  .gallery-grid a:hover{transform:translateY(-4px);box-shadow:var(--kit-shadow)}
  .gallery-grid a:hover img{transform:scale(1.06)}
}

/* ── D1 · buttons: a press you can feel ── */
:where(.btn){transition:transform .2s var(--kit-ease),box-shadow .2s var(--kit-ease)}
.btn:active{transform:scale(.98);transition-duration:.08s}

/* ── D1 · the sticky header gains a soft shadow once the page scrolls under it (motion.js sets html.is-scrolled) ── */
:where(.header){transition:box-shadow .3s var(--kit-ease)}
.is-scrolled .header{box-shadow:0 6px 24px rgba(0,0,0,.10)}

/* ── D1 · the call and quote buttons glow slowly in their own colour. Only the shadow moves, so contrast never changes. ── */
@keyframes kit-glow{0%,100%{box-shadow:0 0 0 0 transparent}50%{box-shadow:0 0 14px 5px color-mix(in srgb,var(--kit-glow,rgba(0,0,0,.25)) 65%,transparent)}}
a.btn[href^="tel:"],a.btn[href$="#request-form"]{animation:kit-glow 2.4s ease-in-out infinite}
a.btn[href^="tel:"]:focus-visible,a.btn[href$="#request-form"]:focus-visible{animation:none}
@media (hover:hover){a.btn[href^="tel:"]:hover,a.btn[href$="#request-form"]:hover{animation:none}}

/* ── D1 · her mark comes in once per page load: a roughly round mark rolls in from the left edge like a wheel
   (motion.js measures the distance and the turn); a wide mark slides in. Her name fades in beside it after. ── */
@keyframes kit-roll-in{from{transform:translateX(calc(-1 * var(--kit-roll-x,100vw))) rotate(calc(-1 * var(--kit-roll-r,720deg)))}to{transform:none}}
@keyframes kit-slide-in{from{opacity:0;transform:translateX(-40px)}to{opacity:1;transform:none}}
@keyframes kit-name-in{from{opacity:0;transform:translateX(-14px)}to{opacity:1;transform:none}}
.kit-logo-roll img.her-logo{animation:kit-roll-in 1.3s cubic-bezier(.22,.61,.36,1) both;will-change:transform}
.kit-logo-slide img.her-logo{animation:kit-slide-in .7s var(--kit-ease) both}
.kit-logo-roll .her-name{animation:kit-name-in .5s ease-out 1.3s both}
.kit-logo-slide .her-name{animation:kit-name-in .5s ease-out .5s both}

/* ── D2 · blog cards (blog-cards.js): the whole card is one link; it lifts with a shadow on hover AND on keyboard focus ── */
.cdd-blog-card{position:relative;transition:transform .35s var(--kit-ease),box-shadow .35s var(--kit-ease)}
.cdd-blog-card__photo{transition:transform .9s var(--kit-ease)}
.cdd-blog-card__more{text-decoration:none}
.cdd-blog-card__more::after{content:"\2192";display:inline-block;margin-left:.4em;transition:transform .35s var(--kit-ease)}
.cdd-blog-card:focus-visible{outline:3px solid currentColor;outline-offset:4px;transform:translateY(-6px);box-shadow:var(--kit-shadow)}
.cdd-blog-card:focus-visible .cdd-blog-card__photo{transform:scale(1.04)}
.cdd-blog-card:focus-visible .cdd-blog-card__more::after{transform:translateX(5px)}
@media (hover:hover){
  .cdd-blog-card:hover{transform:translateY(-6px);box-shadow:var(--kit-shadow)}
  .cdd-blog-card:hover .cdd-blog-card__photo{transform:scale(1.04)}
  .cdd-blog-card:hover .cdd-blog-card__more::after{transform:translateX(5px)}
}
.cdd-blog-card:active{transform:translateY(-2px);transition-duration:.1s}

/* ── C3 · the Home hero slider (hero-slider.js). Only the photo marked is-on shows over the first; with JavaScript off
   or reduced motion the first photo stays. A photo not yet loaded takes no space and shows nothing. ── */
:where([data-hero-slider]){position:relative;overflow:hidden}
/* BATCH 28oct K — `>` : only the LATE slides, the slider's own children. Without it the first photo, written inside its
   <picture> after a <source>, matched `img:not(:first-child)` and was opacity:0 for every visitor with reduced motion
   or JavaScript off. A late slide also carries `hidden` until it has loaded, so its alt text can never show. */
[data-hero-slider] > img:not(:first-child){position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity 1.6s ease-in-out}
[data-hero-slider] > img:not(:first-child).is-on{opacity:1}
[data-hero-slider] img:not([src]){visibility:hidden}
/* BATCH 28oct-ENGINE-FIX-47 — `hidden` HIDES. The author's own CSS gives every hero photo `display:block` (Westside's
   site.css, measured on the staging site 28 Oct), which beats the browser's own `[hidden]{display:none}`, so a late
   slide's alt text could still show. A late slide carries `hidden` until its photo has arrived (hero-slider.js). */
[data-hero-slider] img[hidden]{display:none!important}

/* ── E1 · the quote pop-up (quote.js): the Contact page's own form over the page the visitor is on ── */
.quote-dialog{border:0;padding:0;border-radius:16px;background:#fff;color:#111;width:min(600px,calc(100vw - 32px));max-width:none;max-height:calc(100dvh - 32px);overflow:auto;box-shadow:0 24px 60px rgba(0,0,0,.3)}
.quote-dialog::backdrop{background:rgba(0,0,0,.6)}
.quote-dialog__box{position:relative;padding:clamp(22px,4vw,36px)}
.quote-dialog__box h2{margin-top:0;padding-right:48px}
.quote-dialog form{max-width:none}
.quote-dialog__close{position:absolute;top:10px;right:10px;width:48px;height:48px;border:0;border-radius:999px;background:transparent;color:inherit;font-size:2rem;line-height:1;cursor:pointer}
@media (hover:hover){.quote-dialog__close:hover{background:rgba(0,0,0,.06)}}
.quote-dialog__close:focus-visible{outline:3px solid currentColor;outline-offset:2px}
html.quote-open{overflow:hidden}

/* ── E3 · reCAPTCHA: Google's badge is hidden, so Google's required line sits under each form (captcha.js) ── */
.grecaptcha-badge{visibility:hidden}
.recaptcha-note{margin:.75em 0 0;font-size:.8125rem;line-height:1.4;opacity:.8;max-width:620px}
.recaptcha-note a{color:inherit;text-decoration:underline}

/* ── E6 · the protected email link (mail.js) meets the house 44px tap target in the footer, keyed on the data
   attribute, never on mailto: (the source carries no mailto: at all) ── */
footer a[data-mail],footer a[href^="tel:"]{display:inline-flex;align-items:center;min-height:44px}

/* ── M0 · "Follow us": the label beside her social marks, in every footer and on the Contact page ── */
.kit-follow{display:flex;flex-wrap:wrap;align-items:center;gap:4px 12px}
.kit-follow__label{font-weight:700}
.kit-follow .social-list{margin:0}

/* ── I2 · the engine's 404 page (SiteKit::notFoundPage()) — it sits in her own header and footer ── */
.kit-notfound{padding:clamp(56px,10vw,120px) 0;text-align:center}
.kit-notfound__inner{width:min(720px,100% - 36px);margin:0 auto}
.kit-notfound h1{margin:0 0 .4em}
.kit-notfound p{margin:0 auto 1.6em;max-width:52ch}
.kit-notfound__links{display:flex;flex-wrap:wrap;gap:12px;justify-content:center}

/* ── Everything above is off for a visitor who asks for less motion ── */
@media (prefers-reduced-motion:reduce){
  .kit-reveal-on .kit-reveal{opacity:1!important;transform:none!important;transition:none!important}
  [data-photo] img,[data-lift],.gallery-grid a,.gallery-grid img,.btn,.header,.cdd-blog-card,.cdd-blog-card__photo,
  .cdd-blog-card__more::after,[data-hero-slider] img{transition:none!important}
  [data-photo]:hover img,[data-lift]:hover,.gallery-grid a:hover,.gallery-grid a:hover img,.btn:active,
  .cdd-blog-card:hover,.cdd-blog-card:focus-visible,.cdd-blog-card:active,.cdd-blog-card:hover .cdd-blog-card__photo,
  .cdd-blog-card:focus-visible .cdd-blog-card__photo,.cdd-blog-card:hover .cdd-blog-card__more::after,
  .cdd-blog-card:focus-visible .cdd-blog-card__more::after,
  .kit-reveal-on .kit-reveal:not(.is-in) [data-photo] img,.kit-reveal-on .kit-reveal:not(.is-in)[data-photo] img{transform:none!important}
  a.btn[href^="tel:"],a.btn[href$="#request-form"],img.her-logo,.her-name{animation:none!important}
}

/* ── G1 · her blog from Social Relay's feed (blog.php, post.php — BATCH 25oct BLOG-AND-WORDS): the cards and pager in
   the look blog-cards.js draws, written in the page instead of by a script, and one post in its reading column ── */
.cdd-blog-feed{width:min(1180px,100% - 36px);margin:0 auto;padding:8px 0 56px}
.cdd-blog-card-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:28px;list-style:none;margin:0 0 32px;padding:0}
@media (max-width:640px){.cdd-blog-card-grid{grid-template-columns:1fr}}
.cdd-blog-feed .cdd-blog-card{display:flex;flex-direction:column;height:100%;border:1px solid rgba(0,0,0,.12);border-radius:12px;overflow:hidden;text-decoration:none;color:inherit}
.cdd-blog-feed .cdd-blog-card__photo,.cdd-blog-feed .cdd-blog-card picture img{width:100%;aspect-ratio:16/10;object-fit:cover;display:block}
.cdd-blog-card__body{padding:18px;display:flex;flex-direction:column;gap:8px;flex:1}
.cdd-blog-card__title{font-weight:700;margin:0}
.cdd-blog-card__date{margin:0;font-size:.9em;opacity:.75}
.cdd-blog-card__excerpt{margin:0;opacity:.85;font-size:.95em}
.cdd-blog-feed .cdd-blog-card__more{margin-top:auto;font-weight:600}
.cdd-blog-pager{display:flex;gap:8px;justify-content:center;flex-wrap:wrap;margin:0 0 32px;padding:0}
.cdd-blog-pager a,.cdd-blog-pager span{border:1px solid rgba(0,0,0,.2);color:inherit;border-radius:8px;padding:6px 12px;text-decoration:none;min-width:44px;min-height:44px;box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center}
.cdd-blog-pager [aria-current="page"]{font-weight:700;border-width:2px}
.cdd-blog-empty{text-align:center;margin:24px 0 48px}
.cdd-post-band{width:min(760px,100% - 36px);margin:0 auto;padding:0 0 56px}
a.cdd-blog-back{display:block;width:min(760px,100% - 36px);margin:24px auto 20px;font-weight:600;text-decoration:underline}
.cdd-post__date{margin:-.2em 0 1.2rem;opacity:.75}
.cdd-post__photo{margin:0 0 1.4rem}
.cdd-post__photo img,.cdd-post__body img{max-width:100%;height:auto;border-radius:10px}
.cdd-post__cta{display:flex;flex-wrap:wrap;gap:12px;margin-top:2rem}

/* BATCH 29oct ONE-CLIENT-PAID-RUN FIX 2 (THE-BUILD 62) — A PROTECTED ADDRESS MAY BREAK, SO IT NEVER WIDENS THE PAGE.
   mail.js writes the whole address into a [data-mail] element when the page runs: one unbreakable word. On Rapid
   Lock's footer the author's "Email us" button became "dispatch@rapidlockkey.com.au", the footer column grew to fit
   it, and every page was 422px wide in a 320px phone. */
[data-mail]{overflow-wrap:anywhere;word-break:break-word;max-width:100%;min-width:0}
/* BATCH 9nov RAPID-LOCK-DESKTOP-FAULTS (Rick's rule 3) — the rule above is only the last resort for a page whose
   script never ran: motion.js holds her address on one line and sets it smaller to fit its box, and lets it break
   only if even half its size will not fit. A phone number in her words is held together the same way (.kit-nobr). */
.kit-nobr{white-space:nowrap}
.kit-measure-wrap :is(.kit-nobr,[data-mail],a[href^="tel:"]){white-space:normal!important;overflow-wrap:anywhere!important}
/* BATCH 9nov (Rick's rule 6) — a plain list of photographs is a row of equal tiles (motion.js puts .kit-photo-row on
   a list in <main> whose every item holds only pictures, when her stylesheet left it a plain list). */
.kit-photo-row{list-style:none;padding:0;margin:0 0 1.1em;display:grid;grid-template-columns:repeat(var(--kit-cols,4),minmax(0,1fr));gap:clamp(8px,1.5vw,16px)}
.kit-photo-row > *{margin:0;min-width:0}
.kit-photo-row > * :where(figure){margin:0}
.kit-photo-row > * img{display:block;width:100%;height:auto;aspect-ratio:4/3;object-fit:cover}
/* BATCH 29oct FIX 4 (THE-BUILD 67) — the social mark SiteAuthor::withSocialMarks() writes: a 44px tap target,
   from the kit, never an inline style on the page. */
a[data-cdd-social-mark]{display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px}
/* BATCH 30oct FIX 1 (THE-BUILD 68) — HER HEADER FITS THE PHONE, WHATEVER THE AUTHOR WROTE. On Rapid Lock's 30 Oct
   build the author's brand link was `flex:0 0 auto` with a 128px logo and a 24px name beside it: 376px that could not
   shrink, so every page was 394px wide in a 320px and a 390px phone. On a phone the box holding her logo may now
   shrink and wrap: the name drops under the logo and breaks across lines; the logo keeps its height and is never
   wider than the header. Matched by her logo's own class, so it holds whatever the author calls the link.
   At desktop widths her menu is fitted by motion.js (below), never wrapped into a ragged second row. */
header :is(a,div,span,p):has(> img.her-logo){min-width:0}
/* BATCH 30oct KIT-OWNS-THE-LAYOUT (THE-BUILD 73), REWRITTEN BATCH 9nov RAPID-LOCK-DESKTOP-FAULTS — FROM 768px UP HER
   MENU IS ALWAYS THE FULL DESKTOP ROW, NEVER HER MENU BUTTON (Rick, 6 Nov: the 31 Oct rule moved Rapid Lock's seven
   links into the Menu button at 1389px, and its opened list drew the Services sub-list over four other links).
   motion.js moves her menu's own phone breakpoint to 767px and measures the row (html.kit-menu-desk on every desktop
   or tablet width). If her links do not fit one row: set tighter (kit-menu-tight), then her menu's type smaller,
   never under 14px (kit-menu-small, --kit-menu-size), then her name smaller (never under the brief's 24px); then
   the menu takes its own full row under her logo (kit-menu-row), fitted the same way; only if even that row cannot
   hold every link do her links wrap onto balanced rows (kit-menu-wrap). motion.js marks her menu whatever she calls
   it: her Menu button kit-menu-button (the brief's .nav-toggle__label, or a .menu-toggle / burger button), her
   menu's nav kit-menu-nav and its list of links kit-menu-list (the brief's .nav .nav__list, or any nav > ul). */
.kit-menu-desk header .kit-menu-button{display:none!important}
.kit-menu-tight header .kit-menu-list{gap:0!important}
.kit-menu-tight header .kit-menu-list > li > a{padding-inline:8px!important;letter-spacing:0!important}
.kit-menu-small header .kit-menu-list > li > a{font-size:var(--kit-menu-size)!important}
.kit-menu-row header :has(> .kit-menu-nav){flex-wrap:wrap!important}
.kit-menu-row header .kit-menu-nav{flex-basis:100%!important;order:99;margin-left:0!important}
.kit-menu-row header .kit-menu-list{justify-content:flex-start}
.kit-menu-full header .kit-menu-nav{flex-wrap:wrap!important}
.kit-menu-full header .kit-menu-list{flex:1 1 100%!important}
.kit-menu-wrap header .kit-menu-list{flex-wrap:wrap!important;row-gap:0}
/* · a sub-list opens BELOW its link as a dropdown over the page, on hover or keyboard focus, never in the row and
     never over another menu link (on two rows of links it opens below the lowest row). */
.kit-menu-desk header .kit-menu-list > li:has(> ul){position:relative}
.kit-menu-wrap header .kit-menu-nav{position:relative}
.kit-menu-wrap header .kit-menu-list > li:has(> ul){position:static}
.kit-menu-desk header .kit-menu-list > li > ul{position:absolute!important;top:100%;left:0;z-index:60;display:none!important;flex-direction:column!important;flex-wrap:nowrap!important;margin:0;width:max-content;max-width:min(26rem,calc(100vw - 32px))}
.kit-menu-desk header .kit-menu-list > li:focus-within > ul{display:flex!important}
@media (hover:hover){.kit-menu-desk header .kit-menu-list > li:hover > ul{display:flex!important}}
.kit-menu-desk header .kit-menu-list > li > ul > li > a{width:100%;white-space:nowrap}
/* BATCH 30oct KIT-OWNS-THE-LAYOUT (THE-BUILD 70) — NO PARAGRAPH IN A SLIVER. motion.js puts this on the grid or row
   that crushes a long paragraph under 10 of its own ems (Rapid Lock's price card, 120px wide, 29 lines at 1280). */
.kit-one-col{grid-template-columns:minmax(0,1fr)!important;grid-template-areas:none!important;flex-wrap:wrap!important}
.kit-one-col > *{grid-column:1 / -1!important;flex-basis:100%}
@media (max-width:640px){
  header :is(a,div,span,p):has(> img.her-logo){flex:0 1 auto!important;min-width:0!important;max-width:100%!important;flex-wrap:wrap!important;row-gap:6px}
  header :is(a,div,span,p):has(> img.her-logo) > .her-name{min-width:0;max-width:100%;white-space:normal!important;overflow-wrap:anywhere}
  header img.her-logo{max-width:100%!important}
  /* BATCH 2nov RAPID-LOCK-320 — and wherever else her name sits. Rapid Lock's footer set "Rapid Lock & Key" (20px,
     no-wrap) beside a 44px logo: 322px in a 320px phone on 12 of 13 pages. The header rule above is matched by
     img.her-logo and `header`, so it never reached her footer. Any box holding her name may now wrap, and the
     name wraps between its words. */
  :is(a,div,span,p):has(> .her-name){flex-shrink:1!important;min-width:0;max-width:100%;flex-wrap:wrap;row-gap:6px}
  .her-name{min-width:0;max-width:100%;white-space:normal!important}
}
/* BATCH 2nov RAPID-LOCK-320 — A HEADING OR HER NAME IS NEVER WIDER THAN ITS BOX. Rapid Lock's 2 Nov h1 "Car keys and
   fobs, cut and programmed on-site" reached 348px in a 320px phone: one word was wider than its panel, and the
   break-word rule below (BATCH 1nov #22) names paragraphs and lists, never a heading. motion.js (fitWords) first
   sets the heading smaller until its longest word fits; a word still wider than its box at that floor breaks at
   the edge here. `break-word`, not `anywhere`, so no box changes width: a heading that already fits is untouched. */
:where(h1,h2,h3,h4,h5,h6,.her-name){overflow-wrap:break-word}
/*  · and a link standing on its own (Bloom Room's "hello@thebloomroom.com.au" big link, 325px in a 320px phone).
    A link in a paragraph already breaks with its paragraph. */
:where(main,footer) :where(a){overflow-wrap:break-word}
/*  · a map or video frame is never wider than the column it sits in (Bloom Room's contact map, 304px in a 284px
      column, 344px in a 320px phone). Her own width still sets it; this only stops it at the column's edge. */
:where(main,footer) iframe{max-width:100%}
/* BATCH 30oct EVERY-FAULT-AT-ONCE — her footer, as the visitor reads it.
   · The Follow us block is the kit's own (`.kit-follow`). On Rapid Lock's 30 Oct pages the author also wrote a bare
     "Facebook" link right after it, which became a second Facebook mark under the first on all 13 pages. A lone
     social mark that follows the Follow us block in the same box is that same link again, and is not shown.
   · `.hours` is the kit's day/hours list. Her stylesheet set the grid on the list, not on each day, so every row
     read "Monday:open 24 hours". The day and its hours always have a space between them. */
.kit-follow ~ :is(p,div,span):has(> a[data-cdd-social-mark]:only-child){display:none}
.hours > li > span:first-child{margin-inline-end:.35em}
/* BATCH 1nov KIT-PREVENTS — PAGE FAULTS THE AI KEEPS WRITING, MADE IMPOSSIBLE ON A KIT PAGE. Each rule is :where()
   (no weight at all), so wherever the client's own stylesheet states the thing on purpose, the client's rule wins.
   · #12 a photo given its size keeps its shape: `img{max-width:100%}` with no `height:auto` shrank the width of a
     gallery photo and kept its height="800" (wag-AC7CWP gallery.html: 380×800). The height follows the width.
     A presentational height="" attribute is weaker than any rule, so this beats it; any CSS height beats this. */
:where(img[width][height]){height:auto}
/*  · #15 a jump to a #part lands below the sticky header: motion.js measures the header into --kit-anchor-top
      (unset when the header does not stick, so nothing moves). */
:where([id]){scroll-margin-top:var(--kit-anchor-top,0px)}
/*  · #22 a long link, address or number in the words breaks at the edge instead of running past a 320px phone.
      `break-word`, not `anywhere`: it never changes how wide any box is (min-content is untouched), so a page whose
      words already fit, at any width, lays out exactly as before. Where a long word holds a grid column open,
      motion.js releases that one box (below). */
:where(main) :where(p,li,dd,dt,blockquote,figcaption,address,td,th){overflow-wrap:break-word}
/*  · motion.js (fitGrids) marks a grid in <main> whose column a long word holds open past the grid's edge; its
      children may then shrink to the column, and the words above wrap inside it. */
:where(.kit-fit > *){min-width:0}
/*  BATCH 13nov RAPID-LOCK-READY — motion.js (fitCrumbs, fitDoubleRules): a breadcrumb's separator is drawn after the item
      before it, so a wrapped line never starts with it; a decorative bar just under a box's own coloured top border is
      not drawn as a second rule. */
.kit-crumbs > li[data-kit-sep-was]::before{content:none!important;margin:0!important}
.kit-crumbs > li[data-kit-sep]::after{content:attr(data-kit-sep);margin-left:var(--kit-sep-gap,.5em);color:var(--kit-sep-color,inherit)}
.kit-rule-dup{display:none!important}
