/* ==========================================================================
   LH BARBERSHOP — THE BARBER POLE CURSOR
   Implements 07-operations/decisions/2026-09-14-the-barber-pole-cursor.md
   Construction + the scan it is measured from: 05-design/assets/barber-pole/
   Behaviour: assets/js/barber-pole-cursor.js

   ONE NUMBER SETS THE OBJECT. --bpc-w is the width of the pole's widest band,
   and every other dimension is a span measured off the supplied photograph's
   own alpha silhouette, carried in the SVG's viewBox rather than restated
   here. The pole is 1 : 4.111 because the photograph is.

     --bpc-w   12px    -> the pole stands 49px. A native arrow is ~12 x 19,
                          so this is a tall object and it is kept NARROW for
                          that reason: 12px of width is what a line of type
                          can carry beside it. It is 12 and not 11 so that the
                          drawn pole and the native one in § THE TWO POLES are
                          the SAME SIZE — 12 x 49 both, hotspot on a whole
                          pixel at 6 0 — and the handoff between them is a
                          swap rather than a resize.
     --bpc-tilt 0deg    the pole stands UPRIGHT, which is how a barber pole
                          stands. It is an ORIENTATION and it never animates —
                          the brief rules out rotating the whole cursor around
                          the hotspot, and the turn belongs to the spiral alone.
                          It was leaned 16deg in the first cut so its mass fell
                          down-and-right out of the reading line; upright it
                          hangs straight down from the hotspot instead, and the
                          45px directly under the pointer is the cost. The
                          token is kept so the lean is one number away.

   THE HOTSPOT IS THE TOP FINIAL'S APEX, viewBox (179.5, 0) — the horizontal
   centre of the box and its very top edge. So the layer is offset by half of
   --bpc-w and nothing vertically, and the same point is the origin of both
   the tilt and every scale: the pole grows and presses AROUND the hotspot,
   which is the only way a scale can be applied to a cursor without moving
   the place the click will land.

   TWO THINGS CHANGE AND NOTHING ELSE. Scale, and the rate of the turn.

   NOTHING IN THIS FILE READS THE GROUND. A barber pole is red, white and blue
   on any ground in the world, and one that recoloured itself per section
   would stop reading as an object and start reading as a UI state. The
   keyline used to be the exception — paper on a dark chapter, ink on a light
   one — and it is not any more: see § THE KEYLINE. With it went the script's
   per-frame luminance test, which had no other consumer.
   ========================================================================== */

:root{
  --bpc-w:12px;                      /* the pole's widest band                */
  --bpc-tilt:0deg;                   /* upright. orientation, never animated  */
  --bpc-dur:180ms;                   /* the state response: quick and smooth  */
  --bpc-fade:80ms;                   /* show/hide: a swap, not a dissolve     */
  --bpc-press:90ms;                  /* the click: briefer still              */
  --bpc-ease:cubic-bezier(.22,1,.36,1);

  /* THE PALETTE, MEASURED OFF THE PHOTOGRAPH AND THEN SPENT ON THE SITE.
     Its stripe means are (186,42,44), (34,68,122) and (223,222,223); its
     brass mean is (179,150,98). Two of the four move, and both move ONTO a
     token the site already owns — the white becomes --paper and the brass
     anchor becomes --gold — which is the whole of "integrate with the brand
     environment". The red and the navy are the photograph's, untouched: they
     are the trade's colours, not LH's, and they are why the object reads. */
  --bpc-red:#B0282B;
  --bpc-navy:#22447A;
  --bpc-white:var(--paper,#F3F1EC);
}

/* ── THE TWO POLES ───────────────────────────────────────────────────────
   There are two cursors in this file and they are the SAME OBJECT: the drawn
   pole in the layer below, and a native SVG cursor that is the same measured
   silhouette flattened to flat fills — plus the two dark glass rims, which
   are the one piece of the material pass doing structural work at 12px —
   hotspot on the finial apex at 6 0.

   THE READER ALWAYS HOLDS A BARBER POLE. That is the contract, and the three
   rules below are the whole of it. The native pole is the ground state, on
   everything, always. `bpc-on` — which barber-pole-cursor.js puts on the root
   only while the drawn pole is actually showing — swaps it for `cursor:none`
   so the drawn one can do the job. The moment the drawn one is down, the
   native one is back. There is no third state and no gap between them.

   WHY THE GROUND STATE IS !important, WHICH IS THE BUG THIS FIXES.
   It used to be a plain `html{cursor:url(...)}` — inherited, and therefore
   beaten by every `cursor:pointer` and `cursor:grab` on the site: § 14's
   buttons, the CTA knob, .canvas, .wall, .proof, .acc__trigger. So in any
   moment when the drawn pole was down and `cursor:none` was not applying, the
   reader got the SYSTEM HAND over exactly the things they were most likely to
   be pointing at — a CTA — and LH's pole everywhere else. Reported as "the
   barber pole disappears and the default cursor takes over", and that is
   precisely what it was.

   Held in a custom property so the 5.3KB of path data is written once.
   It is GENERATED, never typed — dev/gen-bpc-fallback.mjs reads the pole the
   script actually built and prints this declaration, which is the only way
   two objects that must stay identical can be kept identical by hand.

   THE CARET IS THE ONE THING THAT BEATS BOTH, and it is last and least
   specific-but-most-specific on purpose: `html input` is (0,0,2) against the
   (0,0,1) of the two rules above it, so it wins over both without needing to
   know which of them is live. `:where()` keeps `.bpc-on` at zero specificity
   for exactly that reason. Over a field the reader is about to type or select
   in, the caret's own I-beam is better information than any object could be. */
:root{
--bpc-cursor:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='49' viewBox='0 0 359 1476'><g fill='%23101011' stroke='%23101011' stroke-width='30' stroke-linejoin='round'><ellipse cx='179.5' cy='52' rx='46' ry='51'/><path d='M5.5 193L30 170A149.5 112 0 0 1 329 170L353.5 193L353.5 244L324.5 281L34.5 281L5.5 244Z'/><rect x='40' y='281' width='279' height='854'/><path d='M40 1135L319 1135L356.5 1196L356.5 1257L332 1273C326 1330 274 1418 225 1418L134 1418C85 1418 33 1330 27 1273L2.5 1257L2.5 1196Z'/><ellipse cx='179.5' cy='1418' rx='45.5' ry='57'/></g><clipPath id='w'><rect x='62' y='281' width='235' height='854'/></clipPath><g clip-path='url(%23w)'><rect fill='%23F3F1EC' x='62' y='281' width='235' height='854'/><path fill='%23B0282B' d='M53.2 -426L59.4 -446.2L77.3 -466.4L105.3 -486.6L140.5 -506.8L179.5 -527L218.5 -547.2L253.7 -567.4L281.7 -587.6L299.6 -607.8L305.8 -628L304.3 -516.9L292.1 -496.7L268.8 -476.5L236.8 -456.3L199.3 -436.1L159.7 -415.9L122.2 -395.7L90.2 -375.5L67 -355.3L54.7 -335.1L53.2 NaNZ'/><path fill='%2322447A' d='M53.2 -224L59.4 -244.2L77.3 -264.4L105.3 -284.6L140.5 -304.8L179.5 -325L218.5 -345.2L253.7 -365.4L281.7 -385.6L299.6 -405.8L305.8 -426L304.3 -314.9L292.1 -294.7L268.8 -274.5L236.8 -254.3L199.3 -234.1L159.7 -213.9L122.2 -193.7L90.2 -173.5L67 -153.3L54.7 -133.1L53.2 NaNZ'/><path fill='%23B0282B' d='M53.2 -22L59.4 -42.2L77.3 -62.4L105.3 -82.6L140.5 -102.8L179.5 -123L218.5 -143.2L253.7 -163.4L281.7 -183.6L299.6 -203.8L305.8 -224L304.3 -112.9L292.1 -92.7L268.8 -72.5L236.8 -52.3L199.3 -32.1L159.7 -11.9L122.2 8.3L90.2 28.5L67 48.7L54.7 68.9L53.2 NaNZ'/><path fill='%2322447A' d='M53.2 180L59.4 159.8L77.3 139.6L105.3 119.4L140.5 99.2L179.5 79L218.5 58.8L253.7 38.6L281.7 18.4L299.6 -1.8L305.8 -22L304.3 89.1L292.1 109.3L268.8 129.5L236.8 149.7L199.3 169.9L159.7 190.1L122.2 210.3L90.2 230.5L67 250.7L54.7 270.9L53.2 NaNZ'/><path fill='%23B0282B' d='M53.2 382L59.4 361.8L77.3 341.6L105.3 321.4L140.5 301.2L179.5 281L218.5 260.8L253.7 240.6L281.7 220.4L299.6 200.2L305.8 180L304.3 291.1L292.1 311.3L268.8 331.5L236.8 351.7L199.3 371.9L159.7 392.1L122.2 412.3L90.2 432.5L67 452.7L54.7 472.9L53.2 NaNZ'/><path fill='%2322447A' d='M53.2 584L59.4 563.8L77.3 543.6L105.3 523.4L140.5 503.2L179.5 483L218.5 462.8L253.7 442.6L281.7 422.4L299.6 402.2L305.8 382L304.3 493.1L292.1 513.3L268.8 533.5L236.8 553.7L199.3 573.9L159.7 594.1L122.2 614.3L90.2 634.5L67 654.7L54.7 674.9L53.2 NaNZ'/><path fill='%23B0282B' d='M53.2 786L59.4 765.8L77.3 745.6L105.3 725.4L140.5 705.2L179.5 685L218.5 664.8L253.7 644.6L281.7 624.4L299.6 604.2L305.8 584L304.3 695.1L292.1 715.3L268.8 735.5L236.8 755.7L199.3 775.9L159.7 796.1L122.2 816.3L90.2 836.5L67 856.7L54.7 876.9L53.2 NaNZ'/><path fill='%2322447A' d='M53.2 988L59.4 967.8L77.3 947.6L105.3 927.4L140.5 907.2L179.5 887L218.5 866.8L253.7 846.6L281.7 826.4L299.6 806.2L305.8 786L304.3 897.1L292.1 917.3L268.8 937.5L236.8 957.7L199.3 977.9L159.7 998.1L122.2 1018.3L90.2 1038.5L67 1058.7L54.7 1078.9L53.2 NaNZ'/><path fill='%23B0282B' d='M53.2 1190L59.4 1169.8L77.3 1149.6L105.3 1129.4L140.5 1109.2L179.5 1089L218.5 1068.8L253.7 1048.6L281.7 1028.4L299.6 1008.2L305.8 988L304.3 1099.1L292.1 1119.3L268.8 1139.5L236.8 1159.7L199.3 1179.9L159.7 1200.1L122.2 1220.3L90.2 1240.5L67 1260.7L54.7 1280.9L53.2 NaNZ'/><path fill='%2322447A' d='M53.2 1392L59.4 1371.8L77.3 1351.6L105.3 1331.4L140.5 1311.2L179.5 1291L218.5 1270.8L253.7 1250.6L281.7 1230.4L299.6 1210.2L305.8 1190L304.3 1301.1L292.1 1321.3L268.8 1341.5L236.8 1361.7L199.3 1381.9L159.7 1402.1L122.2 1422.3L90.2 1442.5L67 1462.7L54.7 1482.9L53.2 NaNZ'/><path fill='%23B0282B' d='M53.2 1594L59.4 1573.8L77.3 1553.6L105.3 1533.4L140.5 1513.2L179.5 1493L218.5 1472.8L253.7 1452.6L281.7 1432.4L299.6 1412.2L305.8 1392L304.3 1503.1L292.1 1523.3L268.8 1543.5L236.8 1563.7L199.3 1583.9L159.7 1604.1L122.2 1624.3L90.2 1644.5L67 1664.7L54.7 1684.9L53.2 NaNZ'/><path fill='%2322447A' d='M53.2 1796L59.4 1775.8L77.3 1755.6L105.3 1735.4L140.5 1715.2L179.5 1695L218.5 1674.8L253.7 1654.6L281.7 1634.4L299.6 1614.2L305.8 1594L304.3 1705.1L292.1 1725.3L268.8 1745.5L236.8 1765.7L199.3 1785.9L159.7 1806.1L122.2 1826.3L90.2 1846.5L67 1866.7L54.7 1886.9L53.2 NaNZ'/><path fill='%23B0282B' d='M53.2 1998L59.4 1977.8L77.3 1957.6L105.3 1937.4L140.5 1917.2L179.5 1897L218.5 1876.8L253.7 1856.6L281.7 1836.4L299.6 1816.2L305.8 1796L304.3 1907.1L292.1 1927.3L268.8 1947.5L236.8 1967.7L199.3 1987.9L159.7 2008.1L122.2 2028.3L90.2 2048.5L67 2068.7L54.7 2088.9L53.2 NaNZ'/><path fill='%2322447A' d='M53.2 2200L59.4 2179.8L77.3 2159.6L105.3 2139.4L140.5 2119.2L179.5 2099L218.5 2078.8L253.7 2058.6L281.7 2038.4L299.6 2018.2L305.8 1998L304.3 2109.1L292.1 2129.3L268.8 2149.5L236.8 2169.7L199.3 2189.9L159.7 2210.1L122.2 2230.3L90.2 2250.5L67 2270.7L54.7 2290.9L53.2 NaNZ'/><rect fill='%230B1016' fill-opacity='.34' x='62' y='281' width='16' height='854'/><rect fill='%230B1016' fill-opacity='.38' x='281' y='281' width='16' height='854'/></g><g fill='%23A8832B'><ellipse cx='179.5' cy='52' rx='46' ry='51'/><path d='M5.5 193L30 170A149.5 112 0 0 1 329 170L353.5 193L353.5 244L324.5 281L34.5 281L5.5 244Z'/><path d='M40 1135L319 1135L356.5 1196L356.5 1257L332 1273C326 1330 274 1418 225 1418L134 1418C85 1418 33 1330 27 1273L2.5 1257L2.5 1196Z'/><ellipse cx='179.5' cy='1418' rx='45.5' ry='57'/><rect x='40' y='281' width='22' height='854'/><rect x='297' y='281' width='22' height='854'/></g></svg>") 6 0, default;
}

@media (hover:hover) and (pointer:fine){
  /* 1 · the ground state: LH's pole, over everything, beating the site's own
         pointer/grab affordances — which `cursor:none` was already taking
         away in the other state, so nothing is lost that was not lost. */
  html, html *{cursor:var(--bpc-cursor) !important}

  /* 2 · …and out of the way while the drawn pole is up. `bpc-on` is added and
         removed in lockstep with the pole's own visibility; see `show()` in
         barber-pole-cursor.js. `bpc-live` no longer gates this — it is set
         once at mount and never cleared, so gating on it meant every moment
         the pole was hidden was a moment with no cursor at all. */
  html:where(.bpc-on), html:where(.bpc-on) *{cursor:none !important}

  /* 3 · the caret, over both. */
  html input:not([type=button]):not([type=submit]):not([type=checkbox]):not([type=radio]),
  html textarea,
  html [contenteditable=""],
  html [contenteditable="true"]{cursor:text !important}
}

/* ── THE LAYER ───────────────────────────────────────────────────────────
   Above everything, inert, and positioned ONLY by transform — the two custom
   properties written per move are consumed inside a translate3d, so a pointer
   move costs a composite and never a layout. */
.bpc{
  position:fixed; left:0; top:0; z-index:2147483000;
  pointer-events:none; opacity:0;
  transform:translate3d(calc(var(--bpc-x,0px) - var(--bpc-w) / 2), var(--bpc-y,0px), 0);
  transition:opacity var(--bpc-fade) linear;
  will-change:transform;
}
.bpc.is-in{opacity:1}

/* the object. width is the token; height is the token times the photograph's
   own aspect, so the two can never drift apart. */
.bpc__pole{
  display:block; overflow:visible;
  width:var(--bpc-w); height:calc(var(--bpc-w) * 4.1114);
  transform-origin:50% 0;                       /* = the hotspot, always      */
  rotate:var(--bpc-tilt);
  scale:calc(var(--bpc-scale,1) * var(--bpc-squash,1));
  transition:scale var(--bpc-dur) var(--bpc-ease);
}

/* ── THE KEYLINE ─────────────────────────────────────────────────────────
   The whole object, one ink, dilated by half a stroke — the masses drawn a
   second time underneath themselves, so the silhouette never has to be
   written as one outline and no internal edge can leak.

   IT IS ALWAYS INK. It used to flip to paper on a dark chapter, on the
   argument that a rim must be the ground's opposite to survive a photograph.
   What that actually produced was a white halo round the pole on every dark
   plate on the site, and a haloed object reads as a sticker laid on the page
   rather than as a thing standing on it.

   Ink on both grounds is also the site's OWN answer to the same question:
   § 23c frames every photograph on this site with a 1px keyline and
   system.css says of it, in as many words, "Ink, not --rule". The pole is
   framed the way the photographs beside it are framed.

   WHAT CARRIES THE POLE ON A DARK GROUND, now that nothing outlines it: its
   own paper. The white band of the spiral IS --paper, so on ink the object
   is mostly its own brightest colour and needs no help. The keyline is doing
   its work in the other direction — on PAPER, where that same white band is
   the page's exact colour and without an ink edge the spiral would read as
   holes cut in the pole. That is why it is not simply deleted.

   non-scaling-stroke, so the keyline is 1px on a 1px screen and STAYS 1px
   when the pole grows on a link. One that scaled with the object would read
   as a second, thicker outline rather than as the same keyline. */
.bpc__rim .bpc__mass{
  fill:var(--bpc-rim);
  stroke:var(--bpc-rim);
  stroke-width:1.4; stroke-linejoin:round;
  vector-effect:non-scaling-stroke;
}
.bpc{--bpc-rim:var(--ink,#101011)}

/* ── THE THREE MATERIALS ─────────────────────────────────────────────────
   Every fill in the object is one of these fifteen, and they are grouped the
   way the object is: painted metal, glass, brass. The gradients themselves
   are built in the script — see § THE STUDIO there for the lamp they all
   answer to, and for why each ink is the colour it is. This file only says
   which surface gets which.

   WHAT MAKES THREE MATERIALS OUT OF ONE DRAWING is not the colours; it is
   that each one answers the same lamp DIFFERENTLY:

     the spiral is PAINT — matte, it takes the cylinder's form and gives back
       no specular of its own. It is also the only thing here that moves.
     the casing is GLASS — two thin, bright, COOL edges and one narrow
       specular, over a body that is clear through a third of its width and
       near-opaque at both rims. It does not move, and that is what puts it
       in front of the spiral.
     the caps are BRASS — a broad WARM key, a core shadow, a bounce, and the
       turned steps. No edge is ever as bright as the glass's, and no
       highlight is ever as narrow.
   ------------------------------------------------------------------------ */

/* 1 · the paint. The well is the white band of the spiral, so only the red
       and the navy are drawn over it: two paths per turn instead of four, and
       the white can be the site's own --paper rather than a fourth colour
       nobody chose. */
.bpc__well{fill:var(--bpc-white)}
.bpc__red{fill:var(--bpc-red)}
.bpc__navy{fill:var(--bpc-navy)}

/* 2 · the glass. Four layers, and none of them turns — see § 2 in the
       script's render tree for why that is the whole trick. */
.bpc__sock-t{fill:url(#bpcSockT)}
.bpc__sock-b{fill:url(#bpcSockB)}
.bpc__cyl{fill:url(#bpcGlassShade)}
.bpc__spec{fill:url(#bpcGlassLight)}

/* 3 · the brass. Five surfaces, five gradients, one alloy: the caps take the
       object-wide ramp because they span it, the rails take their own because
       they are 22 units wide and a 6% slice of a 359-unit ramp is a taper and
       not a tube, and the finials take radials because they are the only two
       spheres in the object. */
.bpc__brass{fill:url(#bpcBrass)}
.bpc__rail-l{fill:url(#bpcRailL)}
.bpc__rail-r{fill:url(#bpcRailR)}
.bpc__ball-t{fill:url(#bpcBallT)}
.bpc__ball-b{fill:url(#bpcBallB)}
.bpc__turn-t{fill:url(#bpcVT)}
.bpc__turn-b{fill:url(#bpcVB)}
.bpc__dome{fill:url(#bpcDome)}
.bpc__ogee{fill:url(#bpcOgee)}

/* the two seams share one gradient and differ only in weight: the base finial
   is the bigger mass, sits under everything, and has to stay legible as its
   own turned piece at 3px. */
.bpc__groove{fill:url(#bpcGroove); opacity:.8}
.bpc__groove--b{opacity:1}

/* and its history. Six marks, restrained on purpose: see the note above them
   in the script. Above ~.09 they stop reading as a surface and start reading
   as dirt, which is a different object entirely. */
.bpc__mark-l{fill:url(#bpcStreakL); opacity:.075}
.bpc__mark-d{fill:url(#bpcStreakD); opacity:.085}
.bpc__speck{fill:url(#bpcSpeck); opacity:.13}

/* THE TURN, AND WHY NOTHING HERE TRANSITIONS IT. The helix is translated in
   the SVG's own units by a number the script writes every frame. A CSS
   transition racing a per-frame write would give the hand's momentum the
   transition's easing instead of its own, which is the same trap the
   mark-pointer's slot documented. The script owns the number outright. */
.bpc__helix{
  transform:translateY(calc(var(--bpc-spin,0) * 1px));
  will-change:transform;
}

/* ── THE FOUR STATES ─────────────────────────────────────────────────────
   Scale is stated here; the rate of the turn is stated in the script's GAIN
   table, because it is a rate and not a look. Between them they are the whole
   state machine — there is nothing else to change.

   1 · default    1.00   the pole, turning once every 3.4s
   2 · link       1.14   it comes forward and the turn gains (GAIN 2.4)
   3 · picture    1.06   scale ONLY. the brief is explicit, and a photograph
                         is the one ground where extra motion competes with
                         the thing the reader came to look at.
   4 · text         —    the pole stands down and the I-beam comes back
   5 · pressed    x.86   a compression, not a transition: it seats and lets
                         go inside --bpc-press, well under the 180ms of every
                         other response, which is what makes it read as touch
                         rather than as another state. */
.bpc{--bpc-scale:1}
.bpc.is-image{--bpc-scale:1.06}
.bpc.is-link{--bpc-scale:1.14}
.bpc.is-text{opacity:0}
.bpc.is-down .bpc__pole{--bpc-squash:.86; transition-duration:var(--bpc-press)}

/* ── § 6 — REDUCED MOTION ────────────────────────────────────────────────
   The turn is off at the source (the script stops writing --bpc-spin), so the
   spiral is simply a still spiral — which is what a barber pole with its
   motor off is, and it stays perfectly recognisable. What is left to do here
   is take the easing out of the state responses so the pole reports what is
   under the hand without ever animating, and hold the scale at rest: a cursor
   that changes size under a reader who has asked for less motion is the
   change they asked to not have.

   The cursor itself STAYS. It does not impair usability — it tracks the
   pointer exactly, it never lags, and the native I-beam still appears over
   every field. Nothing on this site depends on it to know what is clickable;
   § 5's link underlines and § 14's buttons are unchanged either way. */
@media (prefers-reduced-motion:reduce){
  .bpc,.bpc__pole,.bpc__rim .bpc__mass{transition-duration:1ms !important}
  .bpc__helix{transform:none !important}
  .bpc{--bpc-scale:1 !important}
  .bpc.is-down .bpc__pole{--bpc-squash:1}
}
