/* ============================================================
   KompanyOS — 3 Sided Cube sticker set (shared, reusable)
   The hand-drawn, black-outlined 3SC stickers. The full kit lives in
   assets/stickers/kit/ (70 transparent 512px WebPs, pulled from the
   "KompanyOS - Look & feel direction" Figma); the older, differently-named
   files loose in assets/stickers/ still work and are still used by pages.
   The white sticker border and its shadow are baked into each file, so this
   sheet only handles sizing, tilt and motion.

   Drop-in: <link rel="stylesheet" href="stickers.css"> then
   <img class="kos-sticker md tilt-l" src="assets/stickers/kit/melon.webp" alt="">
   (reference in styles.html §13). No JS. Self-contained — no token set needed;
   the one colour it uses reads the 3SC token, falls back to the
   experience-page token, then to a hex.
   ============================================================ */

/* ---------- base ---------- */
.kos-sticker {
  --kos-sticker-size: 96px;
  --kos-sticker-tilt: 0deg;
  display: inline-block; vertical-align: middle;
  width: var(--kos-sticker-size); height: auto;
  object-fit: contain;
  transform: rotate(var(--kos-sticker-tilt));
  /* decorative art: never let it get dragged out or text-selected */
  -webkit-user-drag: none; user-select: none; pointer-events: none;
}

/* ---------- size ramp ---------- */
.kos-sticker.xs { --kos-sticker-size: 32px; }
.kos-sticker.sm { --kos-sticker-size: 56px; }
.kos-sticker.md { --kos-sticker-size: 96px; }
.kos-sticker.lg { --kos-sticker-size: 148px; }
.kos-sticker.xl { --kos-sticker-size: 220px; }
/* fluid: shrinks on small screens without a media query */
.kos-sticker.fluid { --kos-sticker-size: clamp(56px, 9vw, 148px); }

/* ---------- tilt (stickers are never applied perfectly straight) ---------- */
.kos-sticker.tilt-l  { --kos-sticker-tilt: -7deg; }
.kos-sticker.tilt-r  { --kos-sticker-tilt: 7deg; }
.kos-sticker.tilt-l2 { --kos-sticker-tilt: -15deg; }
.kos-sticker.tilt-r2 { --kos-sticker-tilt: 15deg; }
.kos-sticker.flip    { scale: -1 1; }

/* ---------- optional cast shadow (for stickers laid over artwork) ---------- */
.kos-sticker.shadow {
  filter: drop-shadow(4px 5px 0 var(--cube-ink, var(--ink, rgba(0, 0, 0, .18))));
}

/* ---------- marker geometry: descenders (shared by every highlight) ----------
   A marker painted behind a phrase is an inline-block, so the coloured box is
   the LINE BOX — and a display line-height (1.1) is SHORTER than the font's
   ascender-to-descender run. The tails of p/y/g then fall outside the colour:
   "KompanyOS", "own systems" and "your school's systems" all had their y cut
   off at the bottom edge.

   The fix is to pay for the missing descender room in padding and take it
   straight back in margin: the paint grows downwards, the margin box (which is
   what the line box measures) doesn't, so no headline reflows.

     padding-bottom: calc(<own pad> + var(--kos-hl-drop));
     margin-bottom:  calc(var(--kos-hl-drop) * -1);

   Same idea for a RULE under a phrase (.end-underline, .cube-underline): park
   it below the font's descent line rather than at a % of the line box — a
   percentage lands in a different place in every font, which is how the pink
   rule ended up striking through "KompanyOS".
   Both are em, so they hold at every size. */
:root {
  --kos-hl-drop: .1em;    /* extra paint below a marker, cancelled by margin */
  --kos-rule-drop: .08em; /* how far a rule sits below the descenders */

  /* --kos-hl-band — the other half of the problem, and the better answer where a
     mark can use it. An INLINE mark's background box is the font's whole
     ascent+descent, ~1.44em. At a headline leading (1.1) that box is taller than
     the line, so the colour runs over the words above and below — on the School
     Run hero the yellow swallowed the descenders of the line above by 24px.

     This band paints only the ink: from just under the descenders up to just
     over the cap/ascender line, measured UP FROM THE FONT'S DESCENT LINE, so it
     is the same shape at every size and immune to line-height. A gradient rather
     than a box, so it still clones across a wrapped phrase.

       .mark {
         background-image: linear-gradient(to top,
           transparent var(--kos-hl-floor, .03em),
           var(--c) var(--kos-hl-floor, .03em),
           var(--c) var(--kos-hl-ceil, 1.24em),
           transparent var(--kos-hl-ceil, 1.24em));
         background-repeat: no-repeat;
       }

     Write the gradient at the use site and take only the two offsets from here:
     a var() nested INSIDE a custom property is resolved where that property is
     DECLARED, so parking the whole gradient on :root bakes in the colour
     fallback and every marker paints transparent.

     A headline still needs ~1.25 leading for two marked lines to clear each
     other — below that no marker can fit between the lines. */
  --kos-hl-floor: .03em;  /* band bottom, above the font's descent line */
  --kos-hl-ceil: 1.24em;  /* band top, above the font's descent line */
}

/* ---------- anchored to a headline highlight (the usual treatment) ----------
   3SC hangs the sticker off ONE EDGE of the coloured highlight: the highlight
   reserves room at that edge, so the sticker laps onto the colour and hangs
   past it without ever covering a letter. Same trick as .gt/.gt-sticker in
   hero.css, generalised.

     <h2>Work that <span class="kos-sticker-hl">actually ships
           <img class="kos-sticker anchor tilt-r" src="…/robot.webp" alt=""></span></h2>

   --kos-anchor sets the sticker height AND the room the highlight reserves for
   it, so the two can never drift apart. It's in em, so it tracks the headline.

   This class only positions and reserves space — it never paints. Drop it onto
   an existing highlight (.hl-mark, .mark, .gt, .hl-y) and that highlight keeps
   its own look; set --kos-hl-pad to the host's own inline padding so the
   reserved edge builds on it. Add .tape + --kos-hl-color to have it paint one.

   Everything is gated on the sticker actually being there, so an EMPTY slot is
   just a normal highlight — no reserved gap, no display change. That's what
   makes it safe to mark up a headline before its sticker exists. */
.kos-sticker-hl {
  --kos-anchor: 1.9em;
  position: relative;
}
.kos-sticker-hl:has(> .kos-sticker.anchor) {
  display: inline-block;
  /* the reserved edge — asymmetric, so the words stay clear of the sticker */
  padding-right: calc(var(--kos-hl-pad, .34em) + var(--kos-anchor) * .58);
}
/* anchor to the leading edge instead */
.kos-sticker-hl.at-start:has(> .kos-sticker.anchor) {
  padding-right: var(--kos-hl-pad, .34em);
  padding-left: calc(var(--kos-hl-pad, .34em) + var(--kos-anchor) * .58);
}

/* opt in to having the component paint the tape as well */
.kos-sticker-hl.tape {
  display: inline-block;
  padding: .02em var(--kos-hl-pad, .34em) calc(.02em + var(--kos-hl-drop, .1em));
  margin-bottom: calc(var(--kos-hl-drop, .1em) * -1);
  background-image: linear-gradient(var(--kos-hl-color, transparent), var(--kos-hl-color, transparent));
  background-repeat: no-repeat;
  -webkit-box-decoration-break: clone; box-decoration-break: clone;
}

.kos-sticker.anchor {
  position: absolute; z-index: 2;
  width: auto; height: var(--kos-anchor);
  top: 50%; right: calc(var(--kos-anchor) * -.30); left: auto;
  translate: 0 -50%;
}
.kos-sticker-hl.at-start > .kos-sticker.anchor {
  right: auto; left: calc(var(--kos-anchor) * -.30);
}
/* ride the highlight's top edge rather than sitting centred on it — half on
   the colour, half above it */
.kos-sticker.anchor.raise { top: 0; translate: 0 -52%; }

/* ---------- in a line of text, no highlight ----------
   For a headline with nothing behind it: sits on the text baseline and is
   optically raised, the way 3SC drops a robot or a plane into a bare headline. */
.kos-sticker.inline {
  --kos-sticker-size: clamp(40px, 5vw, 84px);
  vertical-align: baseline;
  margin: 0 .12em -.28em;
  position: relative; top: -.08em;
}

/* ---------- overlapping row ---------- */
.kos-sticker-stack { display: inline-flex; align-items: center; }
.kos-sticker-stack > .kos-sticker + .kos-sticker { margin-left: -1.4rem; }
/* alternate the tilt down the row so a stack never looks stamped */
.kos-sticker-stack > .kos-sticker:nth-child(odd)  { --kos-sticker-tilt: -6deg; }
.kos-sticker-stack > .kos-sticker:nth-child(even) { --kos-sticker-tilt: 8deg; }

/* ---------- pinned onto a container ----------
   .kos-sticker-layer is the positioned parent; each .pin child takes --x/--y
   (any CSS length or %) measured from the layer's top-left. */
.kos-sticker-layer { position: relative; }
.kos-sticker.pin {
  position: absolute; left: var(--x, 0); top: var(--y, 0);
  translate: -50% -50%;
  z-index: 2;
}

/* ---------- motion ---------- */
.kos-sticker.float { animation: kos-sticker-float 4.5s ease-in-out infinite; }
@keyframes kos-sticker-float {
  0%, 100% { transform: rotate(var(--kos-sticker-tilt)) translateY(0); }
  50%      { transform: rotate(var(--kos-sticker-tilt)) translateY(-9px); }
}

/* pop on hover — put .pop on the sticker AND make its container the hover
   target, since the sticker itself is pointer-events:none */
.kos-sticker.pop { transition: transform .18s cubic-bezier(.34, 1.56, .64, 1); }
*:hover > .kos-sticker.pop { transform: rotate(var(--kos-sticker-tilt)) scale(1.12); }



/* ---------- wrapped highlights on a phone ----------
   :has(> .kos-sticker.anchor) above sets display:inline-block so the reserved
   edge and the absolutely-placed sticker have a box to work against. An
   inline-block is a SINGLE box, though — it can never fragment — so a highlight
   that WRAPS paints one rectangle bounding every line, and the ragged edge and
   the leading come out as a slab of colour. (It also makes the
   box-decoration-break:clone that several of the host highlights declare inert:
   clone only decides what each fragment gets, and an inline-block has none.)

   That only bites at phone width, where these headlines actually wrap, so the
   component fragments there instead: display:inline + clone gives one box per
   LINE, each hugging that line's own words.

   The sticker has to follow. `top: 50%` resolves against the union of ALL the
   fragments, so the moment the highlight wrapped it floated to the vertical
   middle BETWEEN the lines. `right` and `bottom` resolve against the LAST
   fragment, and --kos-anchor is sized to the line, so bottom:0 parks it on the
   last line where it belongs — no markup change, and it stays out of flow so
   it can never be pushed onto a line of its own. */
@media (max-width: 820px) {
  .kos-sticker-hl:has(> .kos-sticker.anchor) {
    display: inline;
    -webkit-box-decoration-break: clone; box-decoration-break: clone;
    /* an inline box's padding doesn't affect layout, so this only ever made the
       highlight taller than the line it sits on — which is what let two
       fragments overlap. The content area already covers the descenders, so
       the --kos-hl-drop room an inline-block needed is dead weight here. */
    padding-top: 0; padding-bottom: 0;
  }
  /* and the host needs leading that CLEARS that box (~1.39em, the font's
     ascent+descent). At --lh-head: 1.2 consecutive fragments overlapped each
     other by 5-11px. Scoped with :has() so it only loosens the headings that
     actually carry one of these highlights, not every heading on the page. */
  :is(h1, h2, h3, p):has(> .kos-sticker-hl > .kos-sticker.anchor) { line-height: 1.45; }
  /* bottom:0 alone would bottom-ALIGN the sticker, which moves it on the
     single-line highlights that are most of them — the old top:50% centred it.
     Shifting back down by half the difference between the sticker and one line
     puts its CENTRE on the last line's centre, which is identical to the old
     placement when there is only one fragment and correct when there are two.
     --kos-hl-line is one line of the highlight (its content area plus padding);
     override it where a host runs unusually tight or loose. */
  .kos-sticker-hl:has(> .kos-sticker.anchor) > .kos-sticker.anchor,
  .kos-sticker-hl.at-start:has(> .kos-sticker.anchor) > .kos-sticker.anchor {
    top: auto; bottom: 0;
    translate: 0 calc((var(--kos-anchor) - var(--kos-hl-line, 1.5em)) / 2);
  }
}
