/* Shooting.bg — "range day" design system.

   black #0B0B0A · surface #141413 · ivory #EDEAE3

   Monochrome on purpose. There is no signal colour: the primary action and the
   selected state are ivory on black, the lightest thing on the page, and every
   bit of colour comes from the photography. Depth is soft relief (the tokens
   below): controls are keys lit from the top left, tracks and fields are pressed
   in, and nothing glows.

   Tektur carries headings, prices and numerals: angular cuts that read as range
   hardware (Adam Jagosz). IBM Plex Sans carries everything you actually read.
   Both draw Bulgarian letter shapes, which the browser switches on for
   lang="bg", so Bulgarian headings and text match (Onest, the text face before,
   had only the Russian shapes). The client chose the pair in Sept 2026.

   The motif is the frame: photographs and panels sit inset from the viewport
   in rounded frames, so the page reads as a set of objects, not a template. */

:root {
  color-scheme: dark;
  --bg: #0B0B0A;
  --surface: #141413;
  --surface-2: #1B1B19;
  --line: #292825;
  --line-soft: rgb(237 234 227 / .08);
  --text: #EDEAE3;
  --text-2: #C9C6BF;
  --muted: #9A978F;
  --dim: #6A6862;
  /* The accent is ivory: primary buttons and selected states are the lightest
     thing on the page, and colour comes only from the photography. */
  --accent: #EDEAE3;
  --accent-hi: #FFFFFF;
  --accent-ink: #0B0B0A;
  /* Soft relief (Sept 2026): the one depth system, neumorphism kept quiet. Light
     comes from the top left. A raised key catches a hairline of it on that edge and
     casts a soft shade down and right; a groove or a field is pressed in, the
     reverse. Small numbers on purpose: it should read as the material, not an effect. */
  --key: linear-gradient(145deg, #232321, #151514);
  --key-ivory: linear-gradient(180deg, #F1EFE9, #E6E3DC);
  --raise: inset 1px 1px 0 rgb(255 255 255 / .07), inset -1px -1px 0 rgb(0 0 0 / .4),
           5px 7px 14px -4px rgb(0 0 0 / .7), -3px -3px 10px -4px rgb(237 234 227 / .06);
  --raise-sm: inset 1px 1px 0 rgb(255 255 255 / .07), inset -1px -1px 0 rgb(0 0 0 / .35),
              2px 3px 6px -1px rgb(0 0 0 / .6);
  --raise-ivory-sm: inset 0 1px 0 rgb(255 255 255 / .7), inset 0 -1px 0 rgb(0 0 0 / .08),
                    0 2px 6px -1px rgb(0 0 0 / .55);
  --press: inset 2px 3px 7px rgb(0 0 0 / .6), inset -2px -2px 5px rgb(237 234 227 / .035);
  /* a groove cut into a raised surface: pressed in, and its far lip catches the light */
  --groove: var(--press), 1px 1px 0 rgb(255 255 255 / .05);
  --slab: inset 1px 1px 0 rgb(255 255 255 / .045), 0 28px 56px -28px rgb(0 0 0 / .9);
  /* Buttons are caps. A lit rim on the top edge and a darker skirt along the bottom
     give a cap its height; it sits in a hairline of shadow and casts a soft shade.
     Hover lifts it a pixel; a press sinks it, the skirt and the shade collapse and
     the rim turns to shadow. Every state lists its shadows in the same order and
     with the same inset keywords, so the change animates instead of snapping. */
  --cap: #1C1C1A;
  --cap-hover: #242422;
  --cap-sheen: linear-gradient(180deg, rgb(255 255 255 / .07), rgb(255 255 255 / 0) 55%, rgb(0 0 0 / .14));
  --cap-up: inset 0 1px 0 rgb(255 255 255 / .1), inset 0 -2px 0 rgb(0 0 0 / .45),
            0 0 0 1px rgb(0 0 0 / .6), 0 1px 1px rgb(0 0 0 / .5),
            0 8px 18px -6px rgb(0 0 0 / .75), -3px -4px 12px -6px rgb(237 234 227 / .07);
  --cap-lift: inset 0 1px 0 rgb(255 255 255 / .14), inset 0 -2px 0 rgb(0 0 0 / .45),
              0 0 0 1px rgb(0 0 0 / .6), 0 2px 2px rgb(0 0 0 / .45),
              0 14px 26px -8px rgb(0 0 0 / .8), -4px -5px 14px -6px rgb(237 234 227 / .1);
  --cap-down: inset 0 2px 5px rgb(0 0 0 / .55), inset 0 0 0 rgb(0 0 0 / 0),
              0 0 0 1px rgb(0 0 0 / .6), 0 0 0 rgb(0 0 0 / 0),
              0 2px 4px -2px rgb(0 0 0 / .5), 0 0 0 rgb(237 234 227 / 0);
  /* The ivory cap is flat ivory with a hairline of light on its top edge, lifted by
     its shade alone. With a glossy sheen, a 2px skirt, a black ring and a pale halo it
     looked like a plastic pill (rejected Sept 2026). */
  --cap-ivory: #ECE9E2;
  --cap-ivory-hover: #F6F4EF;
  --cap-ivory-sheen: linear-gradient(180deg, rgb(255 255 255 / .16), rgb(255 255 255 / 0) 60%);
  --cap-ivory-up: inset 0 1px 0 rgb(255 255 255 / .7), inset 0 -1px 0 rgb(0 0 0 / .08),
                  0 1px 2px rgb(0 0 0 / .5), 0 6px 16px -8px rgb(0 0 0 / .8);
  --cap-ivory-lift: inset 0 1px 0 rgb(255 255 255 / .85), inset 0 -1px 0 rgb(0 0 0 / .08),
                    0 2px 3px rgb(0 0 0 / .45), 0 12px 24px -10px rgb(0 0 0 / .85);
  --cap-ivory-down: inset 0 1px 3px rgb(0 0 0 / .2), inset 0 -1px 0 rgb(0 0 0 / 0),
                    0 0 1px rgb(0 0 0 / .5), 0 2px 6px -4px rgb(0 0 0 / .6);
  --ok: #8DBF9D;
  --warn: #A9BCCF;
  --danger: #D9776F;

  --display: 'Tektur', 'Arial Black', system-ui, sans-serif;
  --body: 'IBM Plex Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;

  --r-sm: 12px;
  --r: 18px;
  --r-lg: 28px;
  --pill: 999px;
  --ease: cubic-bezier(.22, 1, .36, 1);
  --ease-io: cubic-bezier(.65, 0, .35, 1);

  --pad: clamp(1.25rem, 4vw, 3rem);
  /* Content column. Sections stay full-bleed; their contents centre inside
     --maxw. Padding, not a wrapper div. */
  --maxw: 80rem;
  --gutter: max(var(--pad), (100% - var(--maxw)) / 2);
  /* Inset of the rounded frames from the viewport edge. */
  --frame: clamp(.5rem, 1vw, .875rem);
  /* Inner padding of a frame, lined up with the page gutter on a wide screen. */
  --frame-pad: max(1.25rem, calc(var(--gutter) - var(--frame)));
  --nav-top: calc(var(--frame) + .6rem);
  /* under 56rem a frame starts here, below the nav bar rather than under it */
  --below-nav: calc(var(--nav-top) + 3.75rem + var(--frame));

  --i-arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14M13 6l6 6-6 6'/%3E%3C/svg%3E");
  --i-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12.5l4.5 4.5L19 7.5'/%3E%3C/svg%3E");
  --i-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23A2A59D' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  /* Checkboxes: an EOTech XPS2 from the shooter's side, drawn to the proportions of EOTech's
     rear-view product shot. Unticked the window is dark; ticked, the 68 MOA ring and dot light. */
  --i-sight: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 50 61'%3E %3Cdefs%3E %3ClinearGradient id='hood' x1='0' y1='.7' x2='0' y2='54' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='0' stop-color='%238A8982'/%3E%3Cstop offset='.03' stop-color='%2345443F'/%3E%3Cstop offset='.1' stop-color='%23222221'/%3E%3Cstop offset='1' stop-color='%23111110'/%3E%3C/linearGradient%3E %3ClinearGradient id='leg' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%2377766F' stop-opacity='.7'/%3E%3Cstop offset='1' stop-color='%2377766F' stop-opacity='0'/%3E%3C/linearGradient%3E %3ClinearGradient id='face' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%23232322'/%3E%3Cstop offset='1' stop-color='%23121211'/%3E%3C/linearGradient%3E %3ClinearGradient id='plate' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%231E1E1D'/%3E%3Cstop offset='1' stop-color='%23131312'/%3E%3C/linearGradient%3E %3ClinearGradient id='bevel' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%23050505'/%3E%3Cstop offset='.72' stop-color='%23121211'/%3E%3Cstop offset='1' stop-color='%2346453F'/%3E%3C/linearGradient%3E %3ClinearGradient id='glass' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%230A0D0F' stop-opacity='.8'/%3E%3Cstop offset='1' stop-color='%230A0D0F' stop-opacity='.55'/%3E%3C/linearGradient%3E %3ClinearGradient id='glare' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%23E4ECEF' stop-opacity='.14'/%3E%3Cstop offset='.45' stop-color='%23E4ECEF' stop-opacity='0'/%3E%3C/linearGradient%3E %3ClinearGradient id='key' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%232C2C2A'/%3E%3Cstop offset='1' stop-color='%231A1A19'/%3E%3C/linearGradient%3E %3CradialGradient id='knob' cx='.4' cy='.35' r='.7'%3E%3Cstop offset='0' stop-color='%232E2E2C'/%3E%3Cstop offset='1' stop-color='%230F0F0E'/%3E%3C/radialGradient%3E %3CradialGradient id='screw' cx='.4' cy='.35' r='.75'%3E%3Cstop offset='0' stop-color='%2363625C'/%3E%3Cstop offset='1' stop-color='%231C1C1B'/%3E%3C/radialGradient%3E %3ClinearGradient id='base' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%231F1F1E'/%3E%3Cstop offset='1' stop-color='%230D0D0C'/%3E%3C/linearGradient%3E %3ClinearGradient id='rail' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%2356554F'/%3E%3Cstop offset='1' stop-color='%232A2A27'/%3E%3C/linearGradient%3E %3Cfilter id='m' x='-5%' y='-5%' width='110%' height='110%' color-interpolation-filters='sRGB'%3E %3CfeGaussianBlur in='SourceAlpha' stdDeviation='.55' result='b'/%3E %3CfeSpecularLighting in='b' surfaceScale='1.8' specularConstant='1.7' specularExponent='32' lighting-color='%23F2EFE8' result='s'%3E%3CfeDistantLight azimuth='225' elevation='28'/%3E%3C/feSpecularLighting%3E %3CfeComposite in='s' in2='SourceAlpha' operator='in' result='t'/%3E %3CfeComposite in='SourceGraphic' in2='t' operator='arithmetic' k2='1' k3='.7'/%3E %3C/filter%3E %3C/defs%3E %3Cpath d='M3.5 29h43v26h-43z' fill='%23101010'/%3E %3Cpath filter='url(%23m)' d='M1.2 53.6h47.6v5.9a1.3 1.3 0 0 1-1.3 1.3H35l-1.5-3.1h-17L15 60.8H2.5a1.3 1.3 0 0 1-1.3-1.3z' fill='url(%23base)'/%3E %3Cpath d='M16.5 57.7h17l1.5 3.1H15z' fill='url(%23rail)'/%3E %3Cpath d='M19 58.2v.9M22 58.2v.9M25 58.2v.9M28 58.2v.9M31 58.2v.9' stroke='%231A1A18' stroke-width='.7'/%3E %3Cpath d='M1.5 53.9h47' stroke='%235E5D58' stroke-width='.4' opacity='.7'/%3E %3Cpath filter='url(%23m)' fill-rule='evenodd' fill='url(%23hood)' d='M9.1.7h31.8a6.6 6.6 0 0 1 6.6 6.6V54h-42.9V7.3A6.6 6.6 0 0 1 9.1.7zM9.1 2.8a4.5 4.5 0 0 0-4.5 4.5V54h40.8V7.3a4.5 4.5 0 0 0-4.5-4.5z'/%3E %3Cpath d='M2.75 53V7.3A6.35 6.35 0 0 1 9.1.95h31.8a6.35 6.35 0 0 1 6.35 6.35' fill='none' stroke='url(%23leg)' stroke-width='.45'/%3E %3Cpath d='M4.85 7.3A4.25 4.25 0 0 1 9.1 3.05h31.8a4.25 4.25 0 0 1 4.25 4.25' fill='none' stroke='%230A0A0A' stroke-width='.4'/%3E %3Cpath filter='url(%23m)' d='M10.9 4.8h28.2a4.4 4.4 0 0 1 4.4 4.4V56h-37V9.2a4.4 4.4 0 0 1 4.4-4.4z' fill='url(%23face)'/%3E %3Cpath d='M6.75 9.2a4.15 4.15 0 0 1 4.15-4.15h28.2a4.15 4.15 0 0 1 4.15 4.15' fill='none' stroke='%23807F78' stroke-width='.4' opacity='.85'/%3E %3Crect x='9.3' y='7.7' width='31.4' height='22.4' rx='3.8' fill='url(%23bevel)'/%3E %3Crect x='10.85' y='8.8' width='28.3' height='20.2' rx='2.9' fill='%23060708'/%3E %3Crect x='10.85' y='8.8' width='28.3' height='20.2' rx='2.9' fill='url(%23glass)'/%3E %3Cpath d='M11.45 11.7v9.4L22.85 9.4h-9.1a2.3 2.3 0 0 0-2.3 2.3z' fill='url(%23glare)'/%3E %3Cpath d='M6.6 32.3h36.8' stroke='%230B0B0A' stroke-width='.5'/%3E %3Crect filter='url(%23m)' x='7.7' y='32.9' width='34.6' height='20.4' rx='2' fill='url(%23plate)'/%3E %3Cpath d='M8.4 33.15h33.2' stroke='%2362615B' stroke-width='.35' opacity='.85'/%3E %3Ccircle cx='11.4' cy='36.8' r='2.3' fill='%230B0B0A'/%3E%3Ccircle cx='11.4' cy='36.8' r='1.7' fill='url(%23screw)'/%3E%3Cpath d='M10.450000000000001 36.8h1.9M11.4 35.849999999999994v1.9' stroke='%230A0A0A' stroke-width='.45'/%3E%3Ccircle cx='38.6' cy='36.8' r='2.3' fill='%230B0B0A'/%3E%3Ccircle cx='38.6' cy='36.8' r='1.7' fill='url(%23screw)'/%3E%3Cpath d='M37.65 36.8h1.9M38.6 35.849999999999994v1.9' stroke='%230A0A0A' stroke-width='.45'/%3E%3Ccircle cx='11.4' cy='55.1' r='2.3' fill='%230B0B0A'/%3E%3Ccircle cx='11.4' cy='55.1' r='1.7' fill='url(%23screw)'/%3E%3Cpath d='M10.450000000000001 55.1h1.9M11.4 54.15v1.9' stroke='%230A0A0A' stroke-width='.45'/%3E%3Ccircle cx='38.6' cy='55.1' r='2.3' fill='%230B0B0A'/%3E%3Ccircle cx='38.6' cy='55.1' r='1.7' fill='url(%23screw)'/%3E%3Cpath d='M37.65 55.1h1.9M38.6 54.15v1.9' stroke='%230A0A0A' stroke-width='.45'/%3E %3Ccircle cx='25' cy='38.5' r='4.5' fill='%230B0B0A'/%3E%3Ccircle filter='url(%23m)' cx='25' cy='38.5' r='4' fill='url(%23knob)'/%3E %3Cpath d='M22.3 36.3a3.4 3.4 0 0 1 4.6-.6' fill='none' stroke='%23716F69' stroke-width='.4' opacity='.8'/%3E %3Cpath d='M9.9 41.05h10.2M29.9 41.05h10.2' stroke='%235E5D58' stroke-width='.4'/%3E%3Cpath d='M9.9 41.5h10.2M29.9 41.5h10.2' stroke='%230B0B0A' stroke-width='.4'/%3E %3Cg fill='%230B0B0A'%3E%3Crect x='10.1' y='42.1' width='9.8' height='7' rx='1.3'/%3E%3Crect x='30.1' y='42.1' width='9.8' height='7' rx='1.3'/%3E%3C/g%3E %3Cg fill='url(%23key)' filter='url(%23m)'%3E%3Crect x='10.7' y='42.6' width='8.6' height='6' rx='1'/%3E%3Crect x='30.7' y='42.6' width='8.6' height='6' rx='1'/%3E%3C/g%3E %3Cpath d='M11.1 42.85h7.8M31.1 42.85h7.8' stroke='%2377766F' stroke-width='.35' opacity='.85'/%3E %3Cpath d='M13 44l2 3.2 2-3.2M33 47.2l2-3.2 2 3.2' fill='none' stroke='%2395948D' stroke-width='.45' stroke-linejoin='round'/%3E %3Cpath d='M20.7 45.6h2.1M27.2 45.6h2.1' stroke='%2355544F' stroke-width='.35'/%3E %3C/svg%3E");
  --i-sight-on: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 50 61'%3E %3Cdefs%3E %3ClinearGradient id='hood' x1='0' y1='.7' x2='0' y2='54' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='0' stop-color='%238A8982'/%3E%3Cstop offset='.03' stop-color='%2345443F'/%3E%3Cstop offset='.1' stop-color='%23222221'/%3E%3Cstop offset='1' stop-color='%23111110'/%3E%3C/linearGradient%3E %3ClinearGradient id='leg' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%2377766F' stop-opacity='.7'/%3E%3Cstop offset='1' stop-color='%2377766F' stop-opacity='0'/%3E%3C/linearGradient%3E %3ClinearGradient id='face' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%23232322'/%3E%3Cstop offset='1' stop-color='%23121211'/%3E%3C/linearGradient%3E %3ClinearGradient id='plate' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%231E1E1D'/%3E%3Cstop offset='1' stop-color='%23131312'/%3E%3C/linearGradient%3E %3ClinearGradient id='bevel' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%23050505'/%3E%3Cstop offset='.72' stop-color='%23121211'/%3E%3Cstop offset='1' stop-color='%2346453F'/%3E%3C/linearGradient%3E %3ClinearGradient id='glass' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%230A0D0F' stop-opacity='.8'/%3E%3Cstop offset='1' stop-color='%230A0D0F' stop-opacity='.55'/%3E%3C/linearGradient%3E %3ClinearGradient id='glare' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%23E4ECEF' stop-opacity='.14'/%3E%3Cstop offset='.45' stop-color='%23E4ECEF' stop-opacity='0'/%3E%3C/linearGradient%3E %3ClinearGradient id='key' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%232C2C2A'/%3E%3Cstop offset='1' stop-color='%231A1A19'/%3E%3C/linearGradient%3E %3CradialGradient id='knob' cx='.4' cy='.35' r='.7'%3E%3Cstop offset='0' stop-color='%232E2E2C'/%3E%3Cstop offset='1' stop-color='%230F0F0E'/%3E%3C/radialGradient%3E %3CradialGradient id='screw' cx='.4' cy='.35' r='.75'%3E%3Cstop offset='0' stop-color='%2363625C'/%3E%3Cstop offset='1' stop-color='%231C1C1B'/%3E%3C/radialGradient%3E %3ClinearGradient id='base' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%231F1F1E'/%3E%3Cstop offset='1' stop-color='%230D0D0C'/%3E%3C/linearGradient%3E %3ClinearGradient id='rail' x2='0' y2='1'%3E%3Cstop offset='0' stop-color='%2356554F'/%3E%3Cstop offset='1' stop-color='%232A2A27'/%3E%3C/linearGradient%3E %3Cfilter id='m' x='-5%' y='-5%' width='110%' height='110%' color-interpolation-filters='sRGB'%3E %3CfeGaussianBlur in='SourceAlpha' stdDeviation='.55' result='b'/%3E %3CfeSpecularLighting in='b' surfaceScale='1.8' specularConstant='1.7' specularExponent='32' lighting-color='%23F2EFE8' result='s'%3E%3CfeDistantLight azimuth='225' elevation='28'/%3E%3C/feSpecularLighting%3E %3CfeComposite in='s' in2='SourceAlpha' operator='in' result='t'/%3E %3CfeComposite in='SourceGraphic' in2='t' operator='arithmetic' k2='1' k3='.7'/%3E %3C/filter%3E%3Cfilter id='bloom' x='-1' y='-1' width='3' height='3'%3E%3CfeGaussianBlur stdDeviation='.6'/%3E%3C/filter%3E%3CradialGradient id='cast' cx='25' cy='18.9' r='13' gradientUnits='userSpaceOnUse'%3E%3Cstop offset='0' stop-color='%23FF3B30' stop-opacity='.14'/%3E%3Cstop offset='1' stop-color='%23FF3B30' stop-opacity='0'/%3E%3C/radialGradient%3E %3C/defs%3E %3Cpath d='M3.5 29h43v26h-43z' fill='%23101010'/%3E %3Cpath filter='url(%23m)' d='M1.2 53.6h47.6v5.9a1.3 1.3 0 0 1-1.3 1.3H35l-1.5-3.1h-17L15 60.8H2.5a1.3 1.3 0 0 1-1.3-1.3z' fill='url(%23base)'/%3E %3Cpath d='M16.5 57.7h17l1.5 3.1H15z' fill='url(%23rail)'/%3E %3Cpath d='M19 58.2v.9M22 58.2v.9M25 58.2v.9M28 58.2v.9M31 58.2v.9' stroke='%231A1A18' stroke-width='.7'/%3E %3Cpath d='M1.5 53.9h47' stroke='%235E5D58' stroke-width='.4' opacity='.7'/%3E %3Cpath filter='url(%23m)' fill-rule='evenodd' fill='url(%23hood)' d='M9.1.7h31.8a6.6 6.6 0 0 1 6.6 6.6V54h-42.9V7.3A6.6 6.6 0 0 1 9.1.7zM9.1 2.8a4.5 4.5 0 0 0-4.5 4.5V54h40.8V7.3a4.5 4.5 0 0 0-4.5-4.5z'/%3E %3Cpath d='M2.75 53V7.3A6.35 6.35 0 0 1 9.1.95h31.8a6.35 6.35 0 0 1 6.35 6.35' fill='none' stroke='url(%23leg)' stroke-width='.45'/%3E %3Cpath d='M4.85 7.3A4.25 4.25 0 0 1 9.1 3.05h31.8a4.25 4.25 0 0 1 4.25 4.25' fill='none' stroke='%230A0A0A' stroke-width='.4'/%3E %3Cpath filter='url(%23m)' d='M10.9 4.8h28.2a4.4 4.4 0 0 1 4.4 4.4V56h-37V9.2a4.4 4.4 0 0 1 4.4-4.4z' fill='url(%23face)'/%3E %3Cpath d='M6.75 9.2a4.15 4.15 0 0 1 4.15-4.15h28.2a4.15 4.15 0 0 1 4.15 4.15' fill='none' stroke='%23807F78' stroke-width='.4' opacity='.85'/%3E %3Crect x='9.3' y='7.7' width='31.4' height='22.4' rx='3.8' fill='url(%23bevel)'/%3E %3Crect x='10.85' y='8.8' width='28.3' height='20.2' rx='2.9' fill='%23060708'/%3E %3Crect x='10.85' y='8.8' width='28.3' height='20.2' rx='2.9' fill='url(%23glass)'/%3E%3Crect x='10.85' y='8.8' width='28.3' height='20.2' rx='2.9' fill='url(%23cast)'/%3E%3Cg fill='none' stroke='%23FF3B30'%3E%3Ccircle cx='25' cy='18.9' r='4.1' stroke-width='1.3' opacity='.5' filter='url(%23bloom)'/%3E%3Ccircle cx='25' cy='18.9' r='4.1' stroke-width='.55'/%3E%3C/g%3E%3Ccircle cx='25' cy='18.9' r='1.1' fill='%23FF3B30' opacity='.55' filter='url(%23bloom)'/%3E%3Ccircle cx='25' cy='18.9' r='.5' fill='%23FF7A6E'/%3E %3Cpath d='M11.45 11.7v9.4L22.85 9.4h-9.1a2.3 2.3 0 0 0-2.3 2.3z' fill='url(%23glare)'/%3E %3Cpath d='M6.6 32.3h36.8' stroke='%230B0B0A' stroke-width='.5'/%3E %3Crect filter='url(%23m)' x='7.7' y='32.9' width='34.6' height='20.4' rx='2' fill='url(%23plate)'/%3E %3Cpath d='M8.4 33.15h33.2' stroke='%2362615B' stroke-width='.35' opacity='.85'/%3E %3Ccircle cx='11.4' cy='36.8' r='2.3' fill='%230B0B0A'/%3E%3Ccircle cx='11.4' cy='36.8' r='1.7' fill='url(%23screw)'/%3E%3Cpath d='M10.450000000000001 36.8h1.9M11.4 35.849999999999994v1.9' stroke='%230A0A0A' stroke-width='.45'/%3E%3Ccircle cx='38.6' cy='36.8' r='2.3' fill='%230B0B0A'/%3E%3Ccircle cx='38.6' cy='36.8' r='1.7' fill='url(%23screw)'/%3E%3Cpath d='M37.65 36.8h1.9M38.6 35.849999999999994v1.9' stroke='%230A0A0A' stroke-width='.45'/%3E%3Ccircle cx='11.4' cy='55.1' r='2.3' fill='%230B0B0A'/%3E%3Ccircle cx='11.4' cy='55.1' r='1.7' fill='url(%23screw)'/%3E%3Cpath d='M10.450000000000001 55.1h1.9M11.4 54.15v1.9' stroke='%230A0A0A' stroke-width='.45'/%3E%3Ccircle cx='38.6' cy='55.1' r='2.3' fill='%230B0B0A'/%3E%3Ccircle cx='38.6' cy='55.1' r='1.7' fill='url(%23screw)'/%3E%3Cpath d='M37.65 55.1h1.9M38.6 54.15v1.9' stroke='%230A0A0A' stroke-width='.45'/%3E %3Ccircle cx='25' cy='38.5' r='4.5' fill='%230B0B0A'/%3E%3Ccircle filter='url(%23m)' cx='25' cy='38.5' r='4' fill='url(%23knob)'/%3E %3Cpath d='M22.3 36.3a3.4 3.4 0 0 1 4.6-.6' fill='none' stroke='%23716F69' stroke-width='.4' opacity='.8'/%3E %3Cpath d='M9.9 41.05h10.2M29.9 41.05h10.2' stroke='%235E5D58' stroke-width='.4'/%3E%3Cpath d='M9.9 41.5h10.2M29.9 41.5h10.2' stroke='%230B0B0A' stroke-width='.4'/%3E %3Cg fill='%230B0B0A'%3E%3Crect x='10.1' y='42.1' width='9.8' height='7' rx='1.3'/%3E%3Crect x='30.1' y='42.1' width='9.8' height='7' rx='1.3'/%3E%3C/g%3E %3Cg fill='url(%23key)' filter='url(%23m)'%3E%3Crect x='10.7' y='42.6' width='8.6' height='6' rx='1'/%3E%3Crect x='30.7' y='42.6' width='8.6' height='6' rx='1'/%3E%3C/g%3E %3Cpath d='M11.1 42.85h7.8M31.1 42.85h7.8' stroke='%2377766F' stroke-width='.35' opacity='.85'/%3E %3Cpath d='M13 44l2 3.2 2-3.2M33 47.2l2-3.2 2 3.2' fill='none' stroke='%2395948D' stroke-width='.45' stroke-linejoin='round'/%3E %3Cpath d='M20.7 45.6h2.1M27.2 45.6h2.1' stroke='%2355544F' stroke-width='.35'/%3E %3C/svg%3E");
}

/* ---------- reset & base ---------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
[hidden] { display: none !important; }
html { -webkit-text-size-adjust: 100%; scroll-padding-top: 6.5rem; }
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--body);
  font-size: 1rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img, video, svg { display: block; max-width: 100%; }
::selection { background: var(--accent); color: var(--accent-ink); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* break-word: a Bulgarian compound can be wider than a phone at display size.
   It only kicks in when a single word genuinely cannot fit. */
h1, h2, h3, .display {
  font-family: var(--display); font-weight: 700; font-stretch: 110%;
  line-height: 1; letter-spacing: -.012em;
  text-wrap: balance; overflow-wrap: break-word;
}
h1 { font-size: clamp(2.5rem, 6.2vw, 5.5rem); line-height: .95; }
h2 { font-size: clamp(1.9rem, 4vw, 3.25rem); }
h3 { font-size: clamp(1.2rem, 1.7vw, 1.45rem); line-height: 1.12; }
@media (max-width: 40rem) { h1, h2, h3, .display { font-stretch: 100%; } }
p { text-wrap: pretty; }
a { color: inherit; }

.lead { font-size: clamp(1.05rem, 1.3vw, 1.2rem); line-height: 1.55; color: var(--text-2); max-width: 38rem; }
.muted { color: var(--muted); }
.center { text-align: center; }
.num { font-family: var(--display); font-weight: 700; font-stretch: 115%; font-variant-numeric: tabular-nums; }

.skip-link { position: absolute; left: -9999px; }
.skip-link:focus { left: 1rem; top: 1rem; z-index: 100; background: var(--accent); color: var(--accent-ink); padding: .6rem 1rem; border-radius: var(--pill); }

/* Page-to-page crossfade, native. The nav keeps its own name so it holds still
   while the page underneath changes. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
  ::view-transition-old(root) { animation: .25s var(--ease-io) both vt-out; }
  ::view-transition-new(root) { animation: .5s var(--ease) both vt-in; }
}
@keyframes vt-out { to { opacity: 0; } }
@keyframes vt-in { from { opacity: 0; transform: translateY(10px); } }

/* ---------- navigation ----------
   A floating bar in soft relief: the links sit in a groove and the current page is
   the one raised key; the language switch is the same groove in miniature. It sits
   inside the hero frame and firms up as the page scrolls. The phone menu is a native popover: Esc, focus and the top layer
   come from the browser, and there is no menu JavaScript at all. */
.nav {
  position: fixed; z-index: 60; top: var(--nav-top);
  left: calc(var(--frame) + .6rem); right: calc(var(--frame) + .6rem);
  pointer-events: none;
}
.nav-bar {
  view-transition-name: nav;
  pointer-events: auto;
  max-width: calc(var(--maxw) + 1.5rem); margin-inline: auto;
  display: flex; align-items: center; gap: .75rem;
  height: 3.75rem; padding: 0 .45rem 0 1.35rem;
  border-radius: var(--pill);
  background: linear-gradient(145deg, rgb(255 255 255 / .05), transparent 45%, rgb(0 0 0 / .2)) rgb(20 20 19 / .74);
  box-shadow: var(--raise), 0 18px 40px -20px rgb(0 0 0 / .8);
  -webkit-backdrop-filter: blur(18px) saturate(1.4);
  backdrop-filter: blur(18px) saturate(1.4);
}
@supports (animation-timeline: scroll()) {
  .nav-bar { animation: nav-firm linear both; animation-timeline: scroll(root block); animation-range: 0 45svh; }
}
@keyframes nav-firm { to { background-color: rgb(20 20 19 / .92); } }

.nav-brand { flex: none; display: flex; align-items: center; padding: .5rem 0; }
/* the client's vector logo, its own grey gradient on transparent, so it sits on glass,
   photos and panels alike — no blend-mode tricks */
.nav-brand img, .nav-sheet-head img { width: 8.5rem; height: auto; }
/* the phone menu's head lines up with the bar to the pixel, so the sheet can open out of it */
.nav-sheet-head { padding: 0 .45rem 0 1.35rem; }

.nav-links {
  display: flex; gap: .15rem; margin-inline: auto; padding: 4px;
  border-radius: var(--pill); background: rgb(0 0 0 / .22); box-shadow: var(--groove);
}
.nav-links a {
  padding: .5rem .95rem; border-radius: var(--pill);
  font-size: .92rem; font-weight: 500; color: rgb(237 234 227 / .66); text-decoration: none;
  transition: color .25s var(--ease), background-color .25s var(--ease);
}
.nav-links a:hover { color: var(--text); background: rgb(237 234 227 / .04); }
.nav-links a[aria-current] { color: var(--text); background: var(--key); box-shadow: var(--raise-sm); }

.nav-end { display: flex; align-items: center; gap: .5rem; flex: none; }
.lang {
  display: inline-flex; padding: 3px; border-radius: var(--pill);
  background: rgb(0 0 0 / .22); box-shadow: var(--groove); font-size: .74rem; font-weight: 600; line-height: 1;
}
.lang > * { padding: .42rem .6rem; border-radius: var(--pill); color: var(--muted); text-decoration: none; transition: color .2s, background-color .2s; }
.lang a:hover { color: var(--text); }
.lang [aria-current] { background: var(--key-ivory); color: var(--bg); box-shadow: var(--raise-ivory-sm); }

/* My bookings, as a round cap the Book button's height; the ivory key on its own page */
.nav-account { display: grid; place-items: center; flex: none; width: 2.65rem; height: 2.65rem; border-radius: 50%; color: var(--text); }
.nav-account svg { width: 1.2rem; height: 1.2rem; }
.nav-book .short { display: none; }
.nav-burger {
  display: none; place-content: center; gap: 5px;
  width: 2.9rem; height: 2.9rem; border: 0; border-radius: 50%; cursor: pointer;
}
.nav-burger span { display: block; width: 18px; height: 2px; border-radius: 2px; background: var(--text); }

@media (max-width: 68rem) {
  .nav-links, .nav-account { display: none; }
  .nav-end { margin-left: auto; }
  .nav-burger { display: grid; }
}
@media (max-width: 34rem) {
  .nav-end .lang { display: none; }
  .nav-book .long { display: none; }
  .nav-book .short { display: inline; }
  .nav-bar, .nav-sheet-head { padding-left: 1.1rem; }
}
/* the smallest phones: a smaller wordmark keeps the burger inside the bar */
@media (max-width: 24rem) {
  .nav-bar { gap: .5rem; }
  .nav-brand img, .nav-sheet-head img { width: 7rem; }
}
/* under 360px "Резервирай" still pushed the burger out; the menu has its own Book button */
@media (max-width: 22.45rem) { .nav-book:lang(bg) { display: none; } }

/* phone menu sheet. Its head is the bar's twin, laid out to the pixel (the same
   padding, wordmark and button place), so the sheet can open out of the bar: see the
   motion below. */
.nav-sheet {
  --side: calc(var(--frame) + .6rem);
  position: fixed; inset: 0; width: 100%; height: 100%; max-width: none; max-height: none;
  margin: 0; border: 0; color: var(--text);
  padding: var(--nav-top) var(--side) calc(var(--frame) + 1rem);
  background: rgb(11 11 10 / .94);
  -webkit-backdrop-filter: blur(22px); backdrop-filter: blur(22px);
  flex-direction: column;
  /* a phone on its side, or a 320x568 one in Bulgarian, is shorter than the menu */
  overflow-y: auto; overscroll-behavior: contain;
}
.nav-sheet:popover-open { display: flex; }
html:has(.nav-sheet:popover-open) { overflow: hidden; }

.nav-sheet-head { display: flex; align-items: center; justify-content: space-between; height: 3.75rem; }
.nav-close {
  position: relative; width: 2.9rem; height: 2.9rem; border: 0; border-radius: 50%; cursor: pointer;
}
.nav-close::before, .nav-close::after {
  content: ''; position: absolute; left: 50%; top: 50%; width: 18px; height: 2px; border-radius: 2px;
  background: var(--text); translate: -50% -50%; rotate: 45deg;
}
.nav-close::after { rotate: -45deg; }

.nav-sheet-links { display: flex; flex-direction: column; margin: 2rem .6rem auto; }
/* the rule under each link is a background, so it can draw in */
.nav-sheet-links a {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: 1rem .5rem;
  background: linear-gradient(var(--line-soft) 0 0) left bottom / 100% 1px no-repeat;
  font-family: var(--display); font-weight: 700; font-stretch: 105%;
  font-size: clamp(1.6rem, 7vw, 2.4rem); line-height: 1.05; text-decoration: none;
  color: var(--text-2); transition: color .2s;
}
.nav-sheet-links a::after {
  content: ''; width: 1.4rem; height: 1.4rem; flex: none; background: var(--dim);
  -webkit-mask: var(--i-arrow) center / contain no-repeat; mask: var(--i-arrow) center / contain no-repeat;
  transition: translate .35s var(--ease), background-color .2s;
}
.nav-sheet-links a[aria-current] { color: var(--accent-hi); }
.nav-sheet-links a[aria-current]::after { background: var(--accent-hi); }
.nav-sheet-links a:active { color: var(--text); }
@media (hover: hover) {
  .nav-sheet-links a:hover { color: var(--text); }
  .nav-sheet-links a:hover::after { background: var(--text); translate: 4px 0; }
}
.nav-sheet-foot { display: flex; flex-wrap: wrap; align-items: center; gap: .75rem; margin: 2rem .6rem 0; }
.nav-sheet-foot .btn-primary { flex: 1 1 100%; }
.nav-sheet-foot .nav-phone { margin-left: auto; color: var(--muted); text-decoration: none; font-weight: 500; }
.nav-sheet-foot > :nth-child(1) { --i: 7; }
.nav-sheet-foot > :nth-child(2) { --i: 8; }
.nav-sheet-foot > :nth-child(3) { --i: 9; }

/* The sheet opens out of the bar. It starts clipped to the bar's own pill and drops to
   fill the screen, while the burger's two bars turn into the close X in the same place
   and the links come into focus one after another, each with its rule drawing in under
   it and its arrow sliding home. Closing runs back into the bar, faster, and the X turns
   back into the burger it covers. The sheet itself transitions (display has to stay on
   while it closes); what's inside plays keyframes, so a hover never waits on a stagger
   delay. Reduced motion just shows it. */
@media (prefers-reduced-motion: no-preference) {
  .nav-sheet {
    --shut: inset(var(--nav-top) var(--side) calc(100% - var(--nav-top) - 3.75rem) round 1.875rem);
    clip-path: var(--shut); opacity: 0;
    transition: clip-path .32s var(--ease-io), opacity .14s linear .18s,
                overlay .32s allow-discrete, display .32s allow-discrete;
  }
  .nav-sheet:popover-open {
    clip-path: inset(0 round 0); opacity: 1;
    transition: clip-path .7s var(--ease), opacity .2s linear,
                overlay .7s allow-discrete, display .7s allow-discrete;
  }
  @starting-style { .nav-sheet:popover-open { clip-path: var(--shut); opacity: 0; } }

  .nav-close::before { --y: -3.5px; }
  .nav-close::after { --y: 3.5px; }
  .nav-sheet:popover-open .nav-close::before, .nav-sheet:popover-open .nav-close::after {
    animation: sheet-x .55s var(--ease) .08s backwards;
  }
  .nav-sheet:not(:popover-open) .nav-close::before, .nav-sheet:not(:popover-open) .nav-close::after {
    rotate: 0deg; translate: -50% calc(-50% + var(--y)); transition: rotate .26s var(--ease-io), translate .26s var(--ease-io);
  }

  .nav-sheet:popover-open :is(.nav-sheet-links a, .nav-sheet-foot > *) {
    animation: sheet-in .65s var(--ease) calc(var(--i, 0) * 45ms + 120ms) backwards;
  }
  .nav-sheet:popover-open .nav-sheet-links a { animation-name: sheet-in, sheet-rule; }
  .nav-sheet:popover-open .nav-sheet-links a::after {
    animation: sheet-arrow .5s var(--ease) calc(var(--i, 0) * 45ms + 320ms) backwards;
  }
  .nav-sheet:not(:popover-open) :is(.nav-sheet-links a, .nav-sheet-foot > *) { opacity: 0; transition: opacity .12s linear; }
}
@keyframes sheet-x { from { rotate: 0deg; translate: -50% calc(-50% + var(--y)); } }
@keyframes sheet-in { from { opacity: 0; translate: 0 1.1rem; filter: blur(5px); } }
@keyframes sheet-rule { from { background-size: 0 1px; } }
@keyframes sheet-arrow { from { opacity: 0; translate: -.8rem 0; } }

/* ---------- buttons, chips, tags ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .55rem;
  min-height: 3.1rem; padding: .8rem 1.45rem;
  border: 1px solid transparent; border-radius: var(--pill);
  background: none; color: var(--text);
  font: 600 .95rem/1.15 var(--body); letter-spacing: -.005em;
  text-align: center; text-decoration: none; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background-color .25s var(--ease), color .25s var(--ease),
              box-shadow .18s var(--ease), transform .18s var(--ease);
}
.btn-primary, .btn-light {
  background: var(--cap-ivory-sheen) var(--cap-ivory); color: var(--accent-ink);
  box-shadow: var(--cap-ivory-up);
}
.btn-ghost { background: var(--cap-sheen) var(--cap); box-shadow: var(--cap-up); text-shadow: 0 -1px 0 rgb(0 0 0 / .6); }

/* the round icon buttons are the same dark cap */
.nav-burger, .nav-close, .nav-account, .rail-btn, .cal-nav, .socials a {
  background: var(--cap-sheen) var(--cap); box-shadow: var(--cap-up);
  transition: background-color .25s var(--ease), color .25s var(--ease), box-shadow .18s var(--ease),
              transform .18s var(--ease), opacity .25s;
}
@media (hover: hover) {
  .btn-primary:hover, .btn-light:hover { background-color: var(--cap-ivory-hover); box-shadow: var(--cap-ivory-lift); transform: translateY(-1px); }
  .btn-ghost:hover, .nav-burger:hover, .nav-close:hover, .nav-account:hover, .rail-btn:hover:not(:disabled),
  .cal-nav:hover:not(:disabled), .socials a:hover {
    background-color: var(--cap-hover); box-shadow: var(--cap-lift); transform: translateY(-1px);
  }
}
.btn-primary:active, .btn-light:active { box-shadow: var(--cap-ivory-down); transform: translateY(1px); }
.btn-ghost:active, .nav-burger:active, .nav-close:active, .nav-account:active, .rail-btn:active:not(:disabled),
.cal-nav:active:not(:disabled), .socials a:active { box-shadow: var(--cap-down); transform: translateY(1px); }
.nav-account[aria-current] { background: var(--key-ivory); color: var(--accent-ink); box-shadow: var(--raise-ivory-sm); }
.btn-sm { min-height: 2.65rem; padding: .55rem 1.1rem; font-size: .88rem; }
.btn-block { width: 100%; }
.btn-arrow::after {
  content: ''; width: 1.05em; height: 1.05em; flex: none; background: currentColor;
  -webkit-mask: var(--i-arrow) center / contain no-repeat; mask: var(--i-arrow) center / contain no-repeat;
  transition: translate .35s var(--ease);
}
@media (hover: hover) { .btn-arrow:hover::after { translate: 3px 0; } }

.chips { display: flex; flex-wrap: wrap; gap: .45rem; list-style: none; padding: 0; }
.chip {
  display: inline-flex; align-items: center; gap: .4rem;
  padding: .36rem .8rem; border-radius: var(--pill);
  border: 1px solid var(--line); background: rgb(237 234 227 / .03);
  font-size: .85rem; line-height: 1.25; color: var(--text-2);
}
.chip b { color: var(--text); font-weight: 600; }
.chip-glass { border-color: rgb(237 234 227 / .14); background: rgb(11 11 10 / .45); -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px); }

.tag {
  position: absolute; z-index: 2; top: .8rem; left: .8rem;
  padding: .32rem .7rem; border-radius: var(--pill);
  background: var(--accent); color: var(--accent-ink);
  font-size: .74rem; font-weight: 700; line-height: 1.2;
}

.checks { list-style: none; padding: 0; display: grid; gap: .65rem; }
.checks li { position: relative; padding-left: 2rem; }
.checks li::before {
  content: ''; position: absolute; left: 0; top: .12em; width: 1.3rem; height: 1.3rem;
  border-radius: 50%; background: rgb(237 234 227 / .14);
}
.checks li::after {
  content: ''; position: absolute; left: .32rem; top: calc(.12em + .32rem); width: .66rem; height: .66rem;
  background: var(--accent);
  -webkit-mask: var(--i-check) center / contain no-repeat; mask: var(--i-check) center / contain no-repeat;
}

/* ---------- sections ---------- */
.section { padding: clamp(4rem, 9vw, 7rem) var(--gutter); }
.section-tight { padding-block: clamp(1.5rem, 3vw, 2.5rem); }
.section-flush { padding-top: 0; }

/* A heading and its explanation side by side: the heading states, the copy
   qualifies, and neither has to shout over a label. */
.sec-head {
  display: grid; grid-template-columns: minmax(0, 1fr); gap: 1rem 3rem; align-items: end;
  margin-bottom: clamp(2rem, 4vw, 3rem);
}
.sec-head h2 { max-width: 15ch; }
.sec-head p { color: var(--muted); font-size: 1.05rem; max-width: 32rem; }
.sec-head-end { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.5rem; }
@media (min-width: 56rem) {
  .sec-head { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); }
  .sec-head > :last-child:not(:first-child) { justify-self: end; }
}

.panel { background: var(--surface); border: 1px solid var(--line-soft); border-radius: var(--r-lg); box-shadow: var(--slab); }

/* ---------- photographic grounds ----------
   One mechanism for every darkened photo: set --photo on the element. The files
   ship pre-graded, so the scrim only has to hold the copy. */
.photo-bg {
  position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background: var(--photo) center / cover;
}
.photo-bg::after {
  content: ''; position: absolute; inset: 0;
  background:
    linear-gradient(to top, rgb(11 11 10 / .86) 0%, rgb(11 11 10 / .32) 42%, transparent 72%),
    linear-gradient(90deg, rgb(11 11 10 / .35), transparent 60%);
}

/* ---------- hero ----------
   The range film, in a rounded frame. main.js attaches the file only on a wide
   viewport, without reduced motion or Save-Data, and never over a still staff
   uploaded — otherwise the poster frame is the hero. */
.vhero {
  position: relative; isolation: isolate; overflow: hidden;
  margin: var(--frame); border-radius: var(--r-lg);
  min-height: calc(100svh - 2 * var(--frame));
  display: grid; grid-template-columns: minmax(0, 1fr); align-content: end; gap: 2rem;
  padding: 8rem var(--frame-pad) clamp(1.25rem, 3.5vw, 3rem);
  /* the logo's card is true black, so the page margin round the frame goes black with
     the film (--card, from main.js); the spread reaches the viewport's corners. The
     media layer always covers this background: black, it can't bleed a light seam
     through the rounded edge's anti-aliasing */
  background: #000;
  box-shadow: 0 0 0 calc(var(--frame) * 1.5 + var(--r-lg)) rgb(0 0 0 / var(--card, 0));
}
.vhero-media { position: absolute; inset: 0; z-index: -1; background: var(--bg); }
.vhero-media video, .vhero-poster { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* the client's footage and stills carry a heavy baked-in vignette; cropping in
   a little puts the black corners outside the frame instead of on the page */
.vhero-media video, .vhero-poster { scale: 1.12; }
.crop img, img.crop { scale: 1.22; }
.vhero-poster { background: var(--photo) center / cover; }
.vhero-media video { opacity: 0; transition: opacity 1.4s ease; }
.vhero-media video.is-playing { opacity: 1; }
/* once the film has faded in over it, the poster goes: through the rounded edge's
   anti-aliasing it drew a light arc on the logo's black */
.vhero-media:has(video.is-playing) .vhero-poster { visibility: hidden; transition: visibility 0s 1.4s; }
.vhero-media::after {  /* the site black would lift the card's true black: it stands down for it */
  content: ''; position: absolute; inset: 0; opacity: calc(1 - var(--card, 0));
  background:
    linear-gradient(to top, rgb(11 11 10 / .84) 0%, rgb(11 11 10 / .28) 40%, transparent 68%),
    linear-gradient(90deg, rgb(11 11 10 / .38), transparent 58%);
}
/* one column: the copy runs up the middle of the frame, so the scrim has to reach it */
@media (max-width: 64rem) {
  .vhero-media::after { background: linear-gradient(to top, rgb(11 11 10 / .86) 0%, rgb(11 11 10 / .5) 55%, rgb(11 11 10 / .12) 85%, transparent); }
}
/* The logo on the hero film's closing black. It is page content, not part of the video,
   so main.js can centre it in the frame, clear of the copy, on any screen shape
   (--mark-y) and fade it in on the film's clock (--mark-o, --mark-blur, --mark-s).
   Invisible until the film drives it. */
.vhero-mark {  /* z-index -1: over the film, under the copy */
  position: absolute; z-index: -1; left: 50%; top: var(--mark-y, 50%);
  width: clamp(18rem, 36vw, 40rem); translate: -50% -50%; pointer-events: none;
}
.vhero-mark img {
  display: block; width: 100%; height: auto;
  opacity: var(--mark-o, 0); filter: blur(var(--mark-blur, 0)); scale: var(--mark-s, 1);
}
.vhero-inner { max-width: 52rem; }
.vhero h1 { font-size: clamp(3.1rem, 10vw, 8.5rem); line-height: .88; margin-bottom: 1.6rem; }
/* each line rises out of its own mask on load */
.vhero h1 .line { display: block; }
.vhero h1 .line > span { display: block; }
.vhero .lead { color: rgb(237 234 227 / .8); max-width: 34rem; }
.hero-actions { display: flex; flex-wrap: wrap; gap: .7rem; margin-top: 2rem; }
/* wide: the headline holds the left, the lead and buttons stand at the right on its baseline */
@media (min-width: 64rem) {
  .vhero-inner {
    --side: 27rem; --gap: clamp(2rem, 5vw, 6rem); container-type: inline-size;
    max-width: none; display: grid; align-items: end; column-gap: var(--gap);
    grid-template-columns: minmax(0, 1fr) minmax(0, var(--side)); grid-template-rows: 1fr auto;
  }
  .vhero h1 { grid-row: 1 / 3; margin-bottom: 0; }
  /* "Тренирай" is 4.77em wide in Tektur 700: fit it to the headline's column */
  :lang(bg) .vhero h1 { font-size: min(8.5rem, (100cqi - var(--side) - var(--gap)) / 4.9); }
  .vhero .lead { grid-column: 2; }
  .vhero .hero-actions { grid-column: 2; margin-top: 1.5rem; }
}
/* "Тренирай" is 5.7em wide: at the heading's 3.1rem floor it breaks on a small phone */
@media (max-width: 30rem) { :lang(bg) .vhero h1 { font-size: min(3.1rem, 14vw); } }

@media (max-width: 48rem) { .hero-actions .btn { flex: 1 1 100%; } }

/* Page entrances (Sept 2026). A hero's title comes into focus like the wordmark on the
   film's end card: out of a soft blur, settling from 4% larger, line by line on the
   home hero. Whatever sits under it (the lead, the facts, the buttons) follows once
   the title is nearly sharp, out of a lighter blur, a beat apart. Titles rising out of
   a hard mask were rejected: the edge slices through big letters, and the client had
   already turned that down in the film ("chopped"). */
@media (prefers-reduced-motion: no-preference) {
  .vhero-poster { animation: settle 2.4s var(--ease) both; }
  .vhero h1 .line > span, h1.rise {
    transform-origin: 0 100%;
    animation: title-in 1.6s var(--ease) both; animation-delay: calc(var(--d, 0) * 140ms + 150ms);
  }
  .rise:not(h1) { animation: rise 1.1s var(--ease) both; animation-delay: calc(var(--d, 0) * 140ms + 300ms); }
}
@keyframes settle { from { transform: scale(1.12); } }
@keyframes title-in { from { opacity: 0; filter: blur(14px); transform: scale(1.04); } }
@keyframes rise { from { opacity: 0; filter: blur(6px); transform: translateY(.6rem); } }

/* The loader (base.html), cut like a film's opening. The wordmark comes into focus on the
   black and creeps towards you, the hero film's push-in. Then it flies past the camera
   while the black parts from the middle: to a widescreen slit, a beat there, then off the
   screen. The page's own entrance waits for it. */
.loader { display: none; }
html.loading { overflow: hidden; }
.loading .loader { position: fixed; inset: 0; z-index: 200; display: grid; place-items: center; }
.loading .loader::before, .loading .loader::after {  /* the black, as two halves overlapping at the middle */
  content: ''; position: absolute; inset: 0 0 49.5%; background: var(--bg);
}
.loading .loader::after { inset: 49.5% 0 0; }
.loader img {
  position: relative; z-index: 1; width: clamp(14rem, 36vw, 40rem); height: auto;
  /* focus is backwards-only, so the exit's transitions own the end state; creep composes
     with the exit's transform */
  animation: focus .8s .1s var(--ease) backwards, creep 4s .1s linear both;
  transition: opacity .35s var(--ease), filter .35s var(--ease), transform .6s cubic-bezier(.55, 0, .9, .4);
}
@keyframes focus { from { opacity: 0; filter: blur(10px); } }
@keyframes creep { from { scale: .96; } to { scale: 1.04; } }
.loading.loaded .loader img { opacity: 0; filter: blur(8px); transform: scale(1.35); }
/* each half is 50.5% tall: at 72% of it, 14% of the screen stays covered top and bottom */
.loading.loaded .loader::before { animation: part-up 1.3s .15s var(--ease-io) both; }
.loading.loaded .loader::after { animation: part-down 1.3s .15s var(--ease-io) both; }
@keyframes part-up { 40%, 58% { translate: 0 -72%; } to { translate: 0 -100%; } }
@keyframes part-down { 40%, 58% { translate: 0 72%; } to { translate: 0 100%; } }
/* the titles hold until the black leaves the widescreen slit, so the slit shows only the picture */
.loading:not(.open) :is(.rise, .typed li, .vhero-poster, .vhero h1 .line > span) { animation-play-state: paused; }

/* Scroll-linked parallax, no JS. scroll(root), not view(): .vhero is
   overflow:hidden, which makes it a scroll container, and a view() timeline
   would measure against a box that never scrolls. Nothing here fades — the
   hero holds the primary CTA. */
@keyframes hero-rise { to { transform: translateY(-4rem); } }
@keyframes hero-push { from { transform: scale(1); } to { transform: scale(1.14) translateY(4%); } }
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .vhero-inner, .vhero-mark { animation: hero-rise linear both; animation-timeline: scroll(root block); animation-range: 0 100svh; }
    .vhero-media { animation: hero-push linear both; animation-timeline: scroll(root block); animation-range: 0 110svh; }
  }
}

/* ---------- page heads ---------- */
.page-head {
  position: relative; isolation: isolate; overflow: hidden;
  margin: var(--frame); border-radius: var(--r-lg);
  min-height: min(70svh, 42rem);
  display: grid; grid-template-columns: minmax(0, 1fr); align-content: end; gap: 1.25rem;
  padding: 8rem var(--frame-pad) clamp(1.75rem, 4vw, 3.25rem);
  background: var(--surface);
}
.page-head h1 { max-width: 16ch; }
.page-head .lead { color: rgb(237 234 227 / .8); }
.page-head .chips { margin-top: .5rem; }
@media (prefers-reduced-motion: no-preference) {
  .page-head .photo-bg { animation: settle 2.2s var(--ease) both; }
}

/* a head with no photograph: booking, legal, confirmation */
.head-plain {
  padding: calc(var(--nav-top) + 3.75rem + clamp(2.5rem, 7vw, 5rem)) var(--gutter) clamp(1.5rem, 3vw, 2.5rem);
  display: grid; gap: 1rem; grid-template-columns: minmax(0, 1fr);
}
.head-plain h1 { max-width: 18ch; }
/* A Bulgarian word can be wider than a phone at display size ("стрелбището",
   "възстановяване"), and break-word then splits it mid-word. No browser hyphenates
   Bulgarian, so on a phone its page heads size to the screen instead. Measured:
   every Bulgarian page head fits whole words from 320px up, the longest being
   the About page's "безопасността." */
@media (max-width: 30rem) { :lang(bg) .page-head h1, :lang(bg) .head-plain h1 { font-size: min(2.5rem, 7.9vw); } }
/* Under 56rem the nav bar stands over the page, not the frame, as for the film band:
   every photo head starts below it, and the home hero fills the rest of the screen. */
@media (max-width: 55.99rem) {
  .vhero, .page-head { margin-top: var(--below-nav); padding-top: 2.5rem; }
  .vhero { min-height: calc(100svh - var(--below-nav) - var(--frame)); }
}
/* Upright under 56rem the film takes the top of the frame and fades into black, and the
   copy sits below it on the black, like the courses reel on a phone. The film is the grid's
   first row, so it ends where the copy begins on any screen and in either language, and its
   fade runs out at the headline. Behind the copy, the 16:9 film showed a fifth of its width
   blown up four times: here it plays its 4:5 cut (data-src-tall, poster --tall), made from
   the same portrait clips at full width. The frame's ground is the page black, true black
   with the film for the logo's card (--card), so the fade meets it without a seam; the black
   round the frame reaches up past the nav for the same reason. A phone on its side keeps the
   film behind the copy. The query is written twice, here and in main.js. */
@media (max-width: 55.99rem) and (min-height: 28rem) {
  .vhero {
    grid-template-rows: minmax(10rem, 1fr) auto; row-gap: 0; padding-top: 0;
    background: color-mix(in srgb, #000 calc(var(--card, 0) * 100%), var(--bg));
    box-shadow: 0 calc(var(--below-nav) / -2) 0 calc(var(--below-nav) / 2 + var(--frame) * 1.5 + var(--r-lg)) rgb(0 0 0 / var(--card, 0));
  }
  .vhero-media {
    position: relative; inset: auto; margin-inline: calc(-1 * var(--frame-pad));
    -webkit-mask: linear-gradient(#000 max(40%, 100% - 9rem), transparent);
    mask: linear-gradient(#000 max(40%, 100% - 9rem), transparent);
  }
  .vhero-media::after { background: none; }
  /* the cut is framed for the top of the row: set it 25% down, so a short row shows that */
  .vhero-media video { object-position: 50% 25%; }
  .vhero-media:not([data-ed-custom]) .vhero-poster { background-image: var(--tall); background-position: 50% 25%; }
}

/* ---------- round arrow buttons (the gallery lightbox) ---------- */
.rail-btn {
  display: grid; place-items: center; width: 3rem; height: 3rem; border-radius: 50%;
  border: 0; color: var(--text); cursor: pointer;
}
.rail-btn::before {
  content: ''; width: 1.15rem; height: 1.15rem; background: currentColor;
  -webkit-mask: var(--i-arrow) center / contain no-repeat; mask: var(--i-arrow) center / contain no-repeat;
}
.rail-btn[data-dir="-1"]::before { rotate: 180deg; }
.rail-btn:disabled { opacity: .3; cursor: default; }

/* ---------- the loadout select (home) ----------
   A game's class screen: the sessions in a groove, the one picked raised like the
   nav's current page, and its loadout in a panel. Each key is a radio and its panel
   follows it in the markup, so the grid places them: the keys one to a row (--row)
   in the first column, every panel in the same cell (under the keys on a phone,
   beside them from 64rem). The groove and the panel's slab are the grid's own
   pseudo-elements, so they hold still while the panels change over. */
.kit {
  position: relative; isolation: isolate; display: grid; grid-template-columns: minmax(0, 1fr);
  grid-template-rows: repeat(var(--n), auto) auto; row-gap: .15rem;
}
.kit::before, .kit::after { content: ''; z-index: -1; grid-column: 1; border-radius: var(--r-lg); }
.kit::before { grid-row: 1 / span var(--n); background: var(--surface); box-shadow: var(--groove); }
.kit::after, .kit-panel { grid-row: -2 / -1; margin-top: 1rem; }
.kit::after { background: var(--surface); border: 1px solid var(--line-soft); box-shadow: var(--slab); }

.kit-key {
  grid-column: 1; grid-row: var(--row); position: relative;
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  margin: 0 .35rem; padding: .7rem 1rem .7rem 1.1rem; border-radius: calc(var(--r-lg) - .35rem);
  font-size: 1rem; font-weight: 400; line-height: 1.25; color: var(--text); cursor: pointer;
  -webkit-tap-highlight-color: transparent; /* the raised key is the feedback; a tap flashed it blue */
  transition: background-color .25s var(--ease), box-shadow .25s var(--ease);
}
.kit-key:first-of-type { margin-top: .35rem; }
.kit-key:last-of-type { margin-bottom: .35rem; }
/* the radio itself is invisible: the key is its label, and it keeps the focus ring */
.kit-key input {
  position: absolute; top: 0; left: 0; width: 1px; height: 1px; min-height: 0;
  margin: 0; padding: 0; opacity: 0; pointer-events: none;
}
.kit-key:has(:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }
.kit-key-name { display: grid; font-weight: 600; font-size: .95rem; }
.kit-key-name small { display: none; margin-top: .15rem; font-weight: 400; font-size: .78rem; color: var(--dim); }
.kit-key b { font-family: var(--display); font-stretch: 110%; font-weight: 700; font-variant-numeric: tabular-nums; }
@media (hover: hover) { .kit-key:not(:has(:checked)):hover { background: rgb(237 234 227 / .05); } }
.kit-key:has(:checked) { background: var(--key-ivory); color: var(--bg); box-shadow: var(--raise-ivory-sm); }
.kit-key:has(:checked) small { color: rgb(11 11 10 / .55); }
/* With main.js the raised key is one slab that slides to each pick, placed from the
   checked key (--x, --y, --w, --h). The keys' words are blended against it
   (difference), so they turn dark wherever the slab is under them, mid-slide too. */
.kit-cursor { display: none; }
.kit.is-live .kit-cursor {
  display: block; position: absolute; top: 0; left: 0; width: var(--w); height: var(--h);
  translate: var(--x) var(--y); border-radius: calc(var(--r-lg) - .35rem); pointer-events: none;
  background: var(--key-ivory); box-shadow: var(--raise-ivory-sm);
  transition: translate .55s var(--ease), width .55s var(--ease), height .55s var(--ease);
}
.kit.is-live .kit-key { mix-blend-mode: difference; }
.kit.is-live .kit-key:has(:checked) { background: none; color: var(--text); box-shadow: none; }
.kit.is-live .kit-key small { color: var(--muted); }

/* A panel that isn't picked is out of the flow and invisible, but still laid out, so
   its lazy photo loads with the section and a pick never waits on the network. The
   old panel goes at once and the new one plays its entrance (below), so two never
   show together. */
.kit-panel {
  --kit-pad: clamp(.6rem, 2.5vw, 1.35rem);
  --kit-r: calc(var(--r-lg) - .45rem); /* the plates on its inset */
  grid-column: 1; position: absolute; inset: 0 0 auto; visibility: hidden;
  display: grid; grid-template-columns: minmax(0, 1fr); gap: .45rem; padding: .45rem;
}
.kit-key:has(:checked) + .kit-panel { position: relative; inset: auto; visibility: visible; }

/* the photo and the tray are plates on the panel's inset; the words line up inside them */
.kit-media { position: relative; overflow: hidden; align-self: start; aspect-ratio: 3 / 2; border-radius: var(--kit-r); background: #000; }
.kit-media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; filter: saturate(.78) contrast(1.05); }
.kit-body { display: flex; flex-direction: column; }
.kit-body h3, .kit-meta, .kit-desc { padding-inline: var(--kit-pad); }
.kit-body h3 { padding-top: 1.1rem; font-size: clamp(1.9rem, 3vw, 2.5rem); }
.kit-meta { margin: .5rem 0 1.1rem; color: var(--muted); font-size: .92rem; }
.kit-meta span:last-child { white-space: nowrap; } /* "Min. 3 people"; the guns and shots before it wrap */
.kit-desc { margin: -.35rem 0 1.25rem; max-width: 34rem; color: var(--text-2); font-size: .95rem; line-height: 1.55; }
/* the loadout: one foam tray, a gun to a line, its silhouette and its round count.
   It sits at the foot of its column, level with the price. */
.kit-guns { list-style: none; margin-top: auto; padding: .2rem 0; border-radius: var(--kit-r); background: var(--bg); box-shadow: var(--press); }
.kit-guns li { display: grid; grid-template-columns: 4.5rem minmax(0, 1fr) auto; align-items: center; column-gap: .9rem; padding: .45rem .95rem; }
.kit-guns li + li { border-top: 1px solid var(--line-soft); }
.kit-guns .art { height: 1.4rem; background: var(--text-2); }
.kit-gun { grid-column: 2; display: grid; font-weight: 600; font-size: .95rem; line-height: 1.25; overflow-wrap: break-word; }
.kit-gun small { font-weight: 400; font-size: .76rem; color: var(--muted); }
.kit-guns b { grid-column: 3; text-align: right; font: 700 1.3rem/1 var(--display); font-stretch: 125%; font-variant-numeric: tabular-nums; }
.kit-guns b small { display: block; margin-top: .2rem; font: 400 .7rem/1.2 var(--body); color: var(--muted); }
/* the price and the button share a line where they fit; where they don't, the
   button takes the whole width under the price rather than hanging off its end */
.kit-foot {
  container-type: inline-size; display: flex; flex-wrap: wrap; align-items: center; gap: .75rem 1rem;
  padding: .9rem var(--kit-pad) .85rem;
}
.kit-foot .btn { margin-left: auto; }
@container (width < 27rem) { .kit-foot .btn { width: 100%; padding-inline: .75rem; } }
.kit ~ .included { margin-top: clamp(1.5rem, 3vw, 2.25rem); }
/* a phone: the gun type and the counter need the room the silhouette gives up */
@media (max-width: 30rem) {
  .kit-guns li { grid-template-columns: 3.25rem minmax(0, 1fr) auto; column-gap: .7rem; padding-inline: .8rem; }
}
/* The photo with the price and the button under it, the name and the loadout beside.
   The photo keeps 3:2 unless the loadout beside it runs longer; then it grows to
   meet the price, which crops it no further than about square (Machine at 1024). */
@media (min-width: 44rem) {
  .kit-panel { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); grid-template-rows: 1fr auto; grid-template-areas: "media body" "foot body"; }
  .kit-media { grid-area: media; place-self: stretch; }  /* both axes, or 3:2 widens it out of its column */
  .kit-body { grid-area: body; }
  .kit-foot { grid-area: foot; align-self: end; }
  .kit-key-name { display: flex; align-items: baseline; gap: .75rem; }
  .kit-key-name small { display: inline; }
  .kit-desc { display: none; }
}
/* Beside the panel the keys are one line each until 80rem: two-line keys made the
   column taller than the panel, and the photo grew to fill it, cropping the Double
   Shot briefing to a square that lost the instructor at 1024. */
@media (min-width: 64rem) {
  .kit { grid-template-columns: minmax(0, 17rem) minmax(0, 1fr); grid-template-rows: repeat(var(--n), 1fr); column-gap: clamp(1.25rem, 2.5vw, 2.5rem); }
  .kit::after, .kit-panel { grid-column: 2; grid-row: 1 / -1; margin-top: 0; }
  .kit-key-name { display: grid; gap: 0; }
  .kit-key-name small { display: none; }
}
/* From 80rem the column beside the photo has room for the session's description too. */
@media (min-width: 80rem) { .kit-key-name small, .kit-desc { display: block; } }
/* A phone, or a phone on its side: the keys are an accordion (Sept 2026). Keys over one
   panel left every loadout under the fold, so a tap only moved the highlight. Here the
   pick's loadout opens under its own key, a slab inside the groove, and each key carries
   its "5 guns · 70 shots" line, since the list is what a phone sees first. main.js
   starts the list folded, keeps a tapped key under the finger while the loadout above it
   folds away, brings it up the screen when its own would open out of sight, and folds it
   on a second tap. No sliding key here (main.js drops .is-live): the key raises itself.
   Without JS the first session is open. The query is repeated in main.js. */
@media (width < 44rem), (width < 64rem) and (height < 32rem) {
  .kit { display: flex; flex-direction: column; gap: .15rem; padding-block: .35rem; }
  .kit::before { position: absolute; inset: 0; }
  .kit::after { content: none; }
  .kit-key:is(:first-of-type, :last-of-type) { margin-block: 0; }
  .kit-key-name small { display: block; color: var(--muted); }
  /* the chevron of the About page's qualifications: a row that opens */
  .kit-key b { margin-left: auto; }
  .kit-key::after {
    content: ''; flex: none; width: 1rem; height: 1rem; margin-left: -.4rem; background: currentColor; opacity: .55;
    -webkit-mask: var(--i-chevron) center / contain no-repeat; mask: var(--i-chevron) center / contain no-repeat;
    transition: rotate .3s var(--ease);
  }
  .kit-key:has(:checked)::after { rotate: 180deg; }
  /* the raised key fades in and out with its loadout instead of switching */
  .kit-key { transition: color .3s var(--ease); }
  .kit-key small { transition: color .3s var(--ease); }
  .kit-key::before {
    content: ''; position: absolute; inset: 0; z-index: -1; border-radius: inherit; opacity: 0;
    background: var(--key-ivory); box-shadow: var(--raise-ivory-sm); transition: opacity .3s var(--ease);
  }
  .kit-key:has(:checked) { background: none; box-shadow: none; }
  .kit-key:has(:checked)::before { opacity: 1; }
  :is(.kit-key:has(:checked) + .kit-panel, .kit-panel.is-closing) {
    --kit-r: calc(var(--r-lg) - .8rem);
    margin: .2rem .35rem 0; border: 1px solid var(--line-soft); border-radius: calc(var(--r-lg) - .35rem);
    background: var(--surface-2); box-shadow: var(--slab);
  }
  /* a loadout folding away (main.js) stays in the groove, cut off as its slab closes up */
  .kit-panel.is-closing { position: relative; inset: auto; visibility: visible; overflow: clip; pointer-events: none; }
  /* the open key already names the session and its guns and shots */
  .kit-tag { display: none; }
  .kit-body h3 { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
}

/* A pick opens its panel the way the site opens a photograph: out of a smaller
   rounded window, settling from a slight zoom. The words rise in a beat apart and the
   guns slide into the tray one after another, each silhouette from the left like a
   gun laid in its foam. The words come up from below when the pick moves down the
   list and down from above when it moves up (data-dir, set by main.js). The first
   panel plays it as the section reveals; without JS nothing waits on it. */
.kit-meta { --d: 1; }
.kit-desc { --d: 2; }
.kit-foot { --d: 3; }
.kit[data-dir="up"] { --dir: -1; }
@media (prefers-reduced-motion: no-preference) {
  .kit.is-visible .kit-key:has(:checked) + .kit-panel .kit-media { animation: kit-open .8s var(--ease) both; }
  .kit.is-visible .kit-key:has(:checked) + .kit-panel .kit-media img { animation: kit-settle 1.4s var(--ease) both; }
  .kit.is-visible .kit-key:has(:checked) + .kit-panel :is(h3, .kit-meta, .kit-desc, .kit-foot) {
    animation: kit-rise .75s var(--ease) both; animation-delay: calc(var(--d, 0) * 70ms + 90ms);
  }
  .kit.is-visible .kit-key:has(:checked) + .kit-panel .kit-guns li {
    animation: kit-rise .6s var(--ease) both; animation-delay: calc(var(--k, 0) * 55ms + 220ms);
  }
  .kit.is-visible .kit-key:has(:checked) + .kit-panel .kit-guns .art {
    animation: kit-slot .9s var(--ease) both; animation-delay: calc(var(--k, 0) * 55ms + 220ms);
  }
  /* A loadout folding away on a phone (.is-closing, main.js) plays it backwards, from the
     bottom up as its slab closes: the price and button go, then the guns slide back out of
     the tray (--guns counts them), then the words, while the photo closes into its window. */
  .kit-panel.is-closing .kit-foot { animation: kit-sink .26s var(--ease) both; }
  .kit-panel.is-closing .kit-guns li { animation: kit-sink .26s var(--ease) both; animation-delay: calc((var(--guns) - 1 - var(--k)) * 22ms + 30ms); }
  .kit-panel.is-closing .kit-guns .art { animation: kit-unslot .3s var(--ease) both; animation-delay: calc((var(--guns) - 1 - var(--k)) * 22ms + 30ms); }
  .kit-panel.is-closing :is(.kit-guns, .kit-desc) { animation: kit-sink .26s var(--ease) both; animation-delay: calc(var(--guns) * 22ms + 30ms); }
  .kit-panel.is-closing .kit-meta { animation: kit-sink .26s var(--ease) both; animation-delay: calc(var(--guns) * 22ms + 60ms); }
  .kit-panel.is-closing .kit-media { animation: kit-shut .4s var(--ease) 80ms both; }
  .kit-panel.is-closing .kit-media img { animation: kit-unsettle .4s var(--ease) 80ms both; }
}
@keyframes kit-open { from { clip-path: inset(7% 7% round var(--kit-r)); } to { clip-path: inset(0 round var(--kit-r)); } }
@keyframes kit-settle { from { scale: 1.12; } }
@keyframes kit-rise { from { opacity: 0; translate: 0 calc(var(--dir, 1) * .8rem); } }
@keyframes kit-slot { from { opacity: 0; translate: -1.75rem 0; } }
@keyframes kit-shut { from { clip-path: inset(0 round var(--kit-r)); } to { clip-path: inset(7% 7% round var(--kit-r)); opacity: 0; } }
@keyframes kit-unsettle { to { scale: 1.08; } }
@keyframes kit-sink { to { opacity: 0; translate: 0 -.6rem; } }
@keyframes kit-unslot { to { opacity: 0; translate: -1.75rem 0; } }

.price { font-family: var(--display); font-weight: 700; font-stretch: 115%; font-size: 1.55rem; line-height: 1; white-space: nowrap; }
.price small { font-family: var(--body); font-stretch: 100%; font-weight: 400; font-size: .8rem; color: var(--muted); margin-left: .25rem; }
.price-lg { font-size: clamp(2rem, 3.5vw, 2.6rem); }

/* ---------- bento photo grid ---------- */
.bento { display: grid; gap: .75rem; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-auto-rows: clamp(9.5rem, 17vw, 15rem); }
.bento > * { position: relative; margin: 0; overflow: hidden; border-radius: var(--r); background: var(--surface); }
.bento img { width: 100%; height: 100%; object-fit: cover; transition: transform 1.4s var(--ease); }
@media (hover: hover) { .bento > :hover img { transform: scale(1.05); } }
.bento figcaption {
  position: absolute; left: .7rem; bottom: .7rem; max-width: calc(100% - 1.4rem);
  padding: .32rem .75rem; border-radius: var(--pill);
  background: rgb(11 11 10 / .55); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  font-size: .8rem; line-height: 1.3; color: var(--text);
}
.bento .m-2 { grid-column: span 2; }
.bento .m-r2 { grid-row: span 2; }
@media (min-width: 56rem) {
  .bento { grid-template-columns: repeat(12, minmax(0, 1fr)); }
  .bento > * { grid-column: span 4; }
  .bento .m-2 { grid-column: span 4; }
  .bento .m-r2 { grid-row: auto; }
  .bento .s-3 { grid-column: span 3; }
  .bento .s-5 { grid-column: span 5; }
  .bento .s-6 { grid-column: span 6; }
  .bento .s-7 { grid-column: span 7; }
  .bento .s-8 { grid-column: span 8; }
  .bento .s-12 { grid-column: 1 / -1; }
  .bento .r-2 { grid-row: span 2; }
}
@media (max-width: 30rem) {
  .bento { grid-template-columns: minmax(0, 1fr); grid-auto-rows: 13rem; }
  .bento > *, .bento .m-2 { grid-column: auto; }
  .bento .m-r2 { grid-row: auto; }
}

/* ---------- split panel (photo + copy in one object) ---------- */
.split-panel {
  display: grid; grid-template-columns: minmax(0, 1fr); overflow: hidden;
  border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--line-soft);
}
.split-panel-body { display: flex; flex-direction: column; justify-content: center; gap: 1.25rem; padding: clamp(1.75rem, 4.5vw, 3.75rem); }
.split-panel-body > p { color: var(--muted); max-width: 32rem; }
.split-panel-media { position: relative; min-height: 18rem; margin: .45rem; border-radius: calc(var(--r-lg) - .45rem); overflow: hidden; }
.split-panel-media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
@media (min-width: 56rem) {
  .split-panel { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .split-panel-media { min-height: 30rem; }
}

/* ---------- the transfer map ----------
   Relief and contours are one raster (scripts/transfer_map.py); roads, pins and
   names sit over it on the same 1000-unit square. The square is scaled like
   object-fit: cover, in container units, so a pin stays on its town whatever shape
   the panel takes while its label keeps its type size. Each road drives itself in,
   pickup to range, when the panel arrives; pointing at a pickup in the list or on
   the map lights its road (main.js). */
.xfer-map { container-type: size; aspect-ratio: 4 / 5; background: var(--bg); }
@media (min-width: 40rem) { .xfer-map { aspect-ratio: 6 / 5; } }
/* On the sessions page it sits between the armoury and the questions' opening panel
   (words left, photo right), so on a wide screen the map takes the left: the two
   panels alternate instead of repeating. A phone reads the words first. */
@media (min-width: 56rem) {
  .xfer { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
  .xfer-map { order: -1; aspect-ratio: auto; }
}
.xfer-canvas { position: absolute; left: 50%; top: 50%; width: 100%; width: max(100cqw, 100cqh); aspect-ratio: 1; translate: -50% -50%; }
.xfer-canvas > svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.xfer-canvas path { fill: none; stroke-linecap: round; stroke-linejoin: round; stroke-dasharray: 1; vector-effect: non-scaling-stroke; }
.xfer-case { stroke: var(--bg); stroke-opacity: .8; stroke-width: 6px; }
.xfer-road { stroke: var(--text); stroke-width: 2px; }

.xfer-pin, .xfer-peak { position: absolute; left: calc(var(--x) * .1%); top: calc(var(--y) * .1%); translate: -50% -50%; }
.xfer-peak { font-size: .74rem; color: var(--muted); white-space: nowrap; }
.xfer-pin { width: .75rem; height: .75rem; border-radius: 50%; border: 2px solid var(--text); background: var(--bg); }
.xfer-pin > span {
  position: absolute; left: calc(100% + .4rem); top: 50%; translate: 0 -50%;
  padding: .22rem .6rem; border-radius: var(--pill); white-space: nowrap;
  background: rgb(11 11 10 / .72); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  font-size: .8rem; font-weight: 600; line-height: 1.25;
}
/* the range: a ring with its reticle ticks; the roads reach it from the north and south */
.xfer-pin.is-range { width: 1.5rem; height: 1.5rem; border-width: 1.5px; background: radial-gradient(circle, var(--text) 0 .15rem, rgb(11 11 10 / .55) .19rem); }
.xfer-pin.is-range::before {
  content: ''; position: absolute; inset: -.55rem; --tick: linear-gradient(var(--text) 0 0);
  background: var(--tick) 50% 0 / 1.5px .5rem, var(--tick) 50% 100% / 1.5px .5rem,
              var(--tick) 0 50% / .5rem 1.5px, var(--tick) 100% 50% / .5rem 1.5px;
  background-repeat: no-repeat;
}
.xfer-pin.is-range > span { left: calc(100% + .8rem); padding: .4rem .7rem; border-radius: var(--r-sm); font: 700 .95rem/1.2 var(--display); }
.xfer-pin small { display: block; font: 400 .72rem/1.3 var(--body); color: var(--muted); }

/* compass and a 20 km bar, measured off the same square as the map */
.xfer-key { position: absolute; left: .9rem; top: .9rem; display: flex; align-items: flex-end; gap: .9rem; font-size: .7rem; line-height: 1; color: var(--text-2); }
.xfer-north { display: grid; justify-items: center; gap: .25rem; font-weight: 700; }
.xfer-north::before { content: ''; width: .6rem; height: .7rem; background: currentColor; clip-path: polygon(50% 0, 100% 100%, 50% 75%, 0 100%); }
.xfer-scale { display: grid; gap: .3rem; }
.xfer-scale::before { content: ''; width: calc(max(100cqw, 100cqh) * 20 / 150); height: .4rem; border: 1.5px solid currentColor; border-top: 0; }

/* the pickups as a movement table: town and fare, then distance and drive under them */
.legs { list-style: none; padding: 0; border-top: 1px solid var(--line-soft); }
.legs li {
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: .15rem .9rem;
  padding: .8rem .1rem; border-bottom: 1px solid var(--line-soft);
}
.legs li::before { content: ''; grid-area: 1 / 1; width: .75rem; height: .75rem; border-radius: 50%; border: 2px solid var(--text); }
.legs-name { grid-area: 1 / 2; font-weight: 600; }
.legs-meta { grid-area: 2 / 2 / auto / -1; font-size: .85rem; color: var(--muted); }
.legs-price { grid-area: 1 / 3; font: 700 1.2rem/1 var(--display); font-stretch: 115%; white-space: nowrap; }
.legs-price small { margin-left: .2rem; font: 400 .78rem/1 var(--body); color: var(--muted); }

.legs li, .xfer-pin, .xfer-canvas g { transition: opacity .35s ease; }
.xfer.is-lit .legs li:not(.is-hot) { opacity: .5; }
.xfer.is-lit :is(.xfer-pin, g)[data-leg]:not(.is-hot) { opacity: .2; }

.js .xfer:not(.is-visible) .xfer-canvas path { stroke-dashoffset: 1; }
.js .xfer:not(.is-visible) .xfer-pin { opacity: 0; }
.js .xfer.is-visible .xfer-canvas path { animation: xfer-drive 1.8s var(--ease-io) calc(.5s + var(--n) * .25s) backwards; }
.js .xfer.is-visible .xfer-pin { animation: xfer-pin .6s var(--ease) calc(.3s + var(--n, 0) * .25s) backwards; }
.js .xfer.is-visible .xfer-pin.is-range { animation-delay: 2.1s; }
@keyframes xfer-drive { from { stroke-dashoffset: 1; } }
@keyframes xfer-pin { from { opacity: 0; scale: .4; } }
@media (prefers-reduced-motion: reduce) { .xfer * { animation: none !important; } }

/* ---------- the film band ----------
   The second drone clip pins while the steps scroll over it. position:sticky, so
   no scroll listener. The one rule: no ancestor may be a scroll container,
   which is why .film never gets overflow:hidden. */
.film { position: relative; --film-top: var(--frame); --film-h: calc(100svh - 2 * var(--frame)); }
/* under 56rem the nav bar stands over the page, not the frame: the frame starts below it */
@media (max-width: 55.99rem) {
  .film { --film-top: var(--below-nav); --film-h: calc(100svh - var(--film-top) - var(--frame)); }
}
.film-media {
  position: sticky; top: var(--film-top); height: var(--film-h);
  margin-inline: var(--frame); border-radius: var(--r-lg); overflow: hidden; background: var(--surface);
}
.film-media video, .film-poster { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.film-poster { background: var(--photo) center / cover; }
.film-media video { opacity: 0; transition: opacity 1.4s ease; }
.film-media video.is-playing { opacity: 1; }
/* the copy sits on the left: shade that side, and pool it where the steps are read */
.film-media::after {
  content: ''; position: absolute; inset: 0;
  background: radial-gradient(40% 75% at 14% 55%, rgb(11 11 10 / .55), transparent 72%),
              linear-gradient(90deg, rgb(11 11 10 / .62), rgb(11 11 10 / .1) 75%);
}
/* The film is a split screen of three portrait panels. A portrait frame only has room
   for the centre one, so the picture is laid out three panels wide (310% of the frame)
   and covers from there: the centre panel always fills the width, whatever the frame's
   shape. Otherwise the side panels show as slivers flickering at the edges as they
   open and close. */
@media (max-aspect-ratio: 4/5) { .film-media video, .film-poster { left: -105%; width: 310%; max-width: none; } }
/* pull the copy back over the pinned frame; the section's height ends up being
   the copy's, which is what gives the sticky layer its travel */
.film-copy {
  position: relative; margin-top: calc(-1 * var(--film-h));
  padding: 22svh calc(var(--gutter) + var(--frame)) 26svh;
}
.film-stage { display: grid; grid-template-columns: minmax(0, 1fr); gap: 2.5rem; }
.film-title h2 { max-width: 12ch; }
/* The steps as one panel with a row each: reduced motion, no JS and a phone on its side.
   Otherwise main.js turns the same list into the sequence below. */
.film-steps {
  list-style: none; margin: 0; padding: .35rem 0; counter-reset: step; max-width: 34rem;
  border-radius: var(--r-lg); background: rgb(20 20 19 / .9); border: 1px solid var(--line-soft); box-shadow: var(--slab);
}
.film-steps li {
  counter-increment: step; display: grid; grid-template-columns: 2.3rem minmax(0, 1fr); column-gap: .85rem;
  padding: 1.35rem clamp(1.2rem, 3vw, 1.7rem);
}
.film-steps li + li { border-top: 1px solid var(--line-soft); }
.film-steps li::before {
  content: counter(step, decimal-leading-zero); grid-row: span 2;
  font: 700 .95rem/1.7 var(--display); font-variant-numeric: tabular-nums; color: var(--dim);
}
.film-steps h3 { font-size: clamp(1.3rem, 2.2vw, 1.55rem); line-height: 1.15; }
.film-step-more { display: grid; }
.film-step-more > div { min-height: 0; }
.film-step-body { margin-top: .5rem; color: var(--text-2); max-width: 40ch; }
.film-step-fact { margin-top: .65rem; color: var(--muted); font-size: .88rem; }
@media (min-width: 56rem) {
  .film-stage { grid-template-columns: minmax(0, 1fr) minmax(0, 30rem); align-items: start; }
  .film-title { position: sticky; top: 42svh; }
}
@media (max-width: 40rem) {
  .film-copy { padding: 50svh calc(var(--gutter) + var(--frame)) 12svh; }
  .film-stage { gap: 1.5rem; }
}

/* The steps as a dock (.is-seq, from main.js: motion allowed; phones below). The stage
   pins with the film. The four steps are keys in a glass bar along its bottom, the nav's
   twin (a bar, a groove, the current key raised), and the bar runs across all three of
   the film's panels. The current step's description is a glass card over its key.
   Each step owns a quarter of the band's scroll. main.js moves .is-on at the quarter
   marks, and the raised key and the card then slide there on their own clock,
   so wherever the scroll stops one step shows whole. Rejected before this (Sept 2026):
   glass cards scrolling up the right, big titles scrubbed by the scroll (two overlapped
   mid-way), and the steps as a list on the left panel alone. */
.film.is-seq {
  --beat: 36svh;
  /* The dock is centred, and the title starts where its glass bar does (6px out from the
     groove), so the title, the bar and the first step's card share one left edge. The
     title crosses the black divider between the film's panels where it has to. --dock-w
     is a percentage on purpose: the dock's width and the stage's padding both resolve
     it against the band's width, so the two never drift apart. */
  --dock-w: min(100% - 2 * (var(--frame) + 1.75rem), 62rem);
  --title-fs: clamp(2.1rem, 3vw, 3.3rem);
  --dock-y: 1.75rem;
  --key-r: 1.25rem;
}
.film.is-seq .film-copy { padding: 0; height: calc(var(--film-h) + 4 * var(--beat)); }
.film.is-seq .film-stage {
  display: block; position: sticky; top: var(--film-top); height: var(--film-h);
  padding: calc(var(--nav-top) + 3.75rem + clamp(1.25rem, 5svh, 3rem)) 0 0 calc((100% - var(--dock-w)) / 2 - 6px);
}
.film.is-seq .film-title { position: static; }
/* three lines: "How a / session / works", "Как / протича / една сесия" (7.1em, the longest) */
.film.is-seq .film-title h2 { position: relative; isolation: isolate; max-width: 7.5em; font-size: var(--title-fs); }
/* The title's own shade: an ellipse around it, in its own em, so it moves and grows with
   it. Over the middle panel's white sleeve the old pool left the title at 1.6:1; this
   holds it at 3:1 or better on every frame of the film (measured). */
.film.is-seq .film-title h2::before {
  content: ''; position: absolute; z-index: -1; left: 50%; top: 50%; width: 16em; height: 8em;
  translate: -50% -50%; pointer-events: none;
  background: radial-gradient(closest-side, rgb(11 11 10 / .6) 55%, rgb(11 11 10 / .4) 72%,
                              rgb(11 11 10 / .15) 88%, transparent);
}
/* the shade along the bottom, under the dock */
.film.is-seq .film-media::after { background: linear-gradient(0deg, rgb(11 11 10 / .45), transparent 38%); }
/* The keys size to their labels and share what room is left, so a long Bulgarian label
   keeps to one line. Where the current key sits and how wide it is (--key-x, --key-w)
   come from main.js. Three layers of glass, all pseudo-elements: the bar under the
   groove (the list's ::before), the card's slab (its ::after) and the raised key (the
   first key's ::after, placed against the list). Not the list's own background: a
   backdrop-filter on the list would make it the backdrop root of everything inside,
   and that glass would blur nothing. No transform or opacity on the list or a key
   either: either makes a stacking context, which would lay the bar over the groove
   and the raised key over the labels. */
.film.is-seq .film-steps {
  position: absolute; left: 0; right: 0; bottom: calc(var(--dock-y) + 6px); margin: 0 auto;
  width: var(--dock-w); max-width: none;
  display: grid; grid-auto-flow: column; grid-auto-columns: auto;
  padding: 4px; border: 0; border-radius: calc(var(--key-r) + 4px);
  background: rgb(0 0 0 / .22); box-shadow: var(--groove);
  container-type: inline-size;
}
.film.is-seq .film-steps::before {
  content: ''; position: absolute; inset: -6px; z-index: -1; border-radius: calc(var(--key-r) + 10px);
  background: linear-gradient(145deg, rgb(255 255 255 / .05), transparent 45%, rgb(0 0 0 / .2)) rgb(20 20 19 / .74);
  box-shadow: var(--raise), 0 18px 40px -20px rgb(0 0 0 / .8);
  -webkit-backdrop-filter: blur(18px) saturate(1.4); backdrop-filter: blur(18px) saturate(1.4);
}
.film.is-seq .film-steps li:first-child::after {
  content: ''; position: absolute; top: 4px; bottom: 4px; left: 0; width: var(--key-w, 0px);
  border-radius: var(--key-r); background: var(--key); box-shadow: var(--raise-sm);
  translate: var(--key-x, 0px) 0; transition: translate .55s var(--ease), width .55s var(--ease);
}
/* A key. Its labels are lifted over the raised key, and the list item itself stays flat,
   so the reveal is off here: the dock arrives with the frame. */
.film.is-seq .film-steps li {
  display: flex; align-items: center; justify-content: center; gap: .6rem; min-width: 0; padding: .7rem 1rem;
  cursor: pointer; opacity: 1; translate: none; transition: none;
}
.film.is-seq .film-steps li + li { border-top: 0; }
.film.is-seq .film-steps li::before {
  position: relative; z-index: 1; grid-row: auto; font-size: .78rem; line-height: 1;
  color: rgb(237 234 227 / .38); transition: color .35s var(--ease);
}
.film.is-seq .film-steps h3 {
  position: relative; z-index: 1; font: 500 .92rem/1.25 var(--body); letter-spacing: 0;
  color: rgb(237 234 227 / .6); transition: color .35s var(--ease);
}
.film.is-seq .film-steps .is-done::before, .film.is-seq .film-steps .is-done h3 { color: rgb(237 234 227 / .76); }
.film.is-seq .film-steps .is-on::before, .film.is-seq .film-steps .is-on h3 { color: var(--text); }
@media (hover: hover) { .film.is-seq .film-steps li:hover h3 { color: var(--text); } }
/* The card is one slab of glass that slides over the current key and takes the height
   of its text (--card-h, measured by main.js). The four texts sit on it in the same
   place and take turns: the old one fades as it leaves, then the new one comes in, so
   no two are ever on screen together and the glass never blinks. */
.film.is-seq .film-steps::after, .film.is-seq .film-step-more {
  --w: min(26rem, 100cqw + 12px);
  position: absolute; left: 0; bottom: calc(100% + 6px + .75rem); width: var(--w);
  translate: clamp(-6px, var(--key-x, 0px) + (var(--key-w, 0px) - var(--w)) / 2, 100cqw + 14px - var(--w)) 0;
}
.film.is-seq .film-steps::after {
  content: ''; height: var(--card-h, 0px); border-radius: var(--r-lg);
  background: linear-gradient(145deg, rgb(255 255 255 / .05), transparent 45%, rgb(0 0 0 / .2)) rgb(20 20 19 / .72);
  box-shadow: var(--raise), 0 24px 48px -24px rgb(0 0 0 / .85);
  -webkit-backdrop-filter: blur(18px) saturate(1.4); backdrop-filter: blur(18px) saturate(1.4);
  transition: translate .6s var(--ease), height .45s var(--ease);
}
.film.is-seq .film-step-more {
  z-index: 1; display: block; padding: 1.1rem 1.35rem 1.2rem;
  opacity: 0; pointer-events: none; cursor: auto;
  transition: opacity .15s ease, translate .6s var(--ease);
}
.film.is-seq .is-on .film-step-more {
  opacity: 1; pointer-events: auto;
  transition: opacity .35s ease .2s, translate .6s var(--ease);
}
.film.is-seq .film-step-more > div { translate: 0 .35rem; transition: translate .5s var(--ease); }
.film.is-seq .is-on .film-step-more > div { translate: 0 0; transition-delay: .2s; }
.film.is-seq .film-step-body { margin: 0; max-width: none; font-size: 1rem; line-height: 1.55; color: rgb(237 234 227 / .9); }
.film.is-seq .film-step-fact { color: rgb(237 234 227 / .6); }
/* A phone, or a tablet held upright: the same bar, standing down the right of the frame
   (.is-seq under 56rem; main.js wants a screen at least 34rem tall for it). Its keys are
   the steps' numbers. Here each step's li is its card, the title over the text, and its
   number (li::before) is placed out into the bar, a fixed step from the card's bottom
   right corner. The four cards stack beside the bar and take turns as above. The raised
   key slides down the bar (--on) and the glass takes the height of the step on show
   (--item-h), both from main.js. The cards take their width from the stage (cqw).
   The title stands large in the room above the cards, four fifths of the way down it:
   near the frame's middle, leaning towards the card. It is placed against the tallest
   card (--tallest, from main.js), so it holds still as the steps change. Rejected (Sept
   2026): jammed into the top corner, small and sat on the card, riding each card. */
@media (max-width: 55.99rem) {
  .film.is-seq {
    --edge: calc(var(--frame) + 1rem); --kh: 2.6rem; --gap: .5rem; --key-r: .85rem;
    --title-fs: clamp(2.3rem, 10.5vw, 3.2rem);
  }
  /* clip: the title's shade would reach past the screen's edge and widen the page */
  .film.is-seq .film-stage { container-type: inline-size; overflow: clip; padding: 0 var(--edge); }
  /* its top is .8 of the room above the tallest card less its own height (translate's %) */
  .film.is-seq .film-title {
    position: absolute; left: var(--edge); right: var(--edge); top: calc(.8 * (var(--film-h) - 1rem));
    translate: 0 calc(-80% - .8 * var(--tallest, 0px));
  }
  /* 6.6em: "How a / session / works" in three (two would leave "works" alone), and
     "Как протича / една сесия" in two */
  .film.is-seq .film-title h2 { max-width: 6.6em; }
  .film.is-seq .film-steps {
    --card-w: min(26rem, 100cqw - var(--kh) - 20px - var(--gap));
    left: auto; right: calc(var(--edge) + 6px); bottom: calc(1rem + 6px); margin: 0;
    width: calc(var(--kh) + 8px); height: calc(4 * var(--kh) + 8px); display: block; container-type: normal;
  }
  .film.is-seq .film-steps li, .film.is-seq .film-steps::after {
    position: absolute; left: auto; right: calc(100% + 6px + var(--gap)); bottom: -6px; width: var(--card-w); translate: none;
  }
  .film.is-seq .film-steps::after { height: var(--item-h, 0px); transition: height .45s var(--ease); }
  .film.is-seq .film-steps li { z-index: 1; display: block; padding: 1rem 1.15rem 1.1rem; cursor: auto; pointer-events: none; }
  /* a key's row in the bar (not --i: the reveal restaggers that) */
  .film.is-seq .film-steps li:nth-child(2) { --row: 1; }
  .film.is-seq .film-steps li:nth-child(3) { --row: 2; }
  .film.is-seq .film-steps li:nth-child(4) { --row: 3; }
  .film.is-seq .film-steps li::before {
    position: absolute; left: calc(100% + var(--gap) + 10px); bottom: calc(10px + (3 - var(--row, 0)) * var(--kh));
    display: grid; place-items: center; width: var(--kh); height: var(--kh);
    font-size: .85rem; pointer-events: auto; cursor: pointer;
  }
  .film.is-seq .film-steps li:first-child::after {
    top: auto; left: calc(100% + var(--gap) + 10px); bottom: calc(10px + 3 * var(--kh));
    width: var(--kh); height: var(--kh);
    translate: 0 calc(var(--on, 0) * var(--kh)); transition: translate .55s var(--ease);
  }
  .film.is-seq .film-steps h3 {
    font: 700 1.2rem/1.15 var(--display); letter-spacing: -.012em; color: var(--text);
    opacity: 0; translate: 0 .35rem; transition: opacity .15s ease, translate .5s var(--ease);
  }
  .film.is-seq .film-steps .is-on h3 { opacity: 1; translate: 0 0; transition: opacity .35s ease .2s, translate .5s var(--ease) .2s; }
  .edit-on .film.is-seq .film-steps .is-on h3 { pointer-events: auto; }
  .film.is-seq .film-step-more { position: static; width: auto; translate: none; padding: 0; margin-top: .5rem; }
  .film.is-seq .film-step-body { font-size: .95rem; line-height: 1.5; }
  .film.is-seq .film-step-fact { margin-top: .5rem; font-size: .82rem; }
  /* the narrowest phones: a smaller card, so the tallest Bulgarian step (the briefing)
     still leaves the title room above it */
  @media (max-width: 22.5rem) {
    .film.is-seq .film-steps li { padding: .85rem .95rem .95rem; }
    .film.is-seq .film-steps h3 { font-size: 1.05rem; }
    .film.is-seq .film-step-body { font-size: .875rem; line-height: 1.45; }
    .film.is-seq .film-step-fact { font-size: .78rem; }
  }
}

/* ---------- notice ---------- */
.notice {
  display: grid; grid-template-columns: auto minmax(0, 1fr); gap: .75rem 1.25rem; align-items: center;
  padding: clamp(1.25rem, 3vw, 1.75rem); border-radius: var(--r-lg);
  background: var(--surface); border: 1px solid var(--line-soft);
}
.notice-icon { display: grid; place-items: center; width: 2.75rem; height: 2.75rem; border-radius: 50%; background: rgb(237 234 227 / .12); color: var(--accent); }
.notice-icon svg { width: 1.3rem; height: 1.3rem; }
.notice-title { font-family: var(--display); font-weight: 700; font-stretch: 110%; font-size: 1.15rem; line-height: 1.2; }
.notice p { color: var(--muted); font-size: .95rem; }
.notice > p:last-child { grid-column: 1 / -1; }
/* on the home page the notice sits between the film band and the CTA frame: the
   film's margin is the gap above it, so the same gap goes below */
.film + .section-tight { padding-block: 0 clamp(2rem, 5vw, 4rem); }
@media (min-width: 56rem) {
  .notice { grid-template-columns: auto minmax(8rem, 12rem) minmax(0, 1fr); align-items: center; }
  .notice > p:last-child { grid-column: auto; }
}

/* ---------- CTA frame ---------- */
.cta {
  position: relative; isolation: isolate; overflow: hidden;
  margin: 0 var(--frame); border-radius: var(--r-lg);
  min-height: min(78svh, 40rem);
  display: grid; align-content: end; justify-items: start; gap: 1.25rem;
  padding: clamp(2rem, 6vw, 4.5rem) var(--frame-pad);
  background: var(--surface);
  view-timeline: --cta block;
}
/* Heavier than the page heads' scrim: the copy runs up the lower half of a bright
   photograph (white shirts on the home one). Measured so the headline holds 3:1 and
   the lead 4.5:1 against the brightest pixels behind them; the top stays clear. */
.cta .photo-bg::after {
  background:
    linear-gradient(to top, rgb(11 11 10 / .92) 0%, rgb(11 11 10 / .78) 40%, rgb(11 11 10 / .45) 65%, transparent 92%),
    linear-gradient(90deg, rgb(11 11 10 / .55), rgb(11 11 10 / .3) 45%, transparent 70%);
}
/* a short screen makes the frame short, so the copy climbs the photo: the home team
   CTA's headline fell to 2.9:1 over the white shirts at 1280x720, 4.6:1 with this */
@media (max-height: 50rem) {
  .cta .photo-bg::after {
    background:
      linear-gradient(to top, rgb(11 11 10 / .92) 0%, rgb(11 11 10 / .8) 48%, rgb(11 11 10 / .5) 72%, transparent 95%),
      linear-gradient(90deg, rgb(11 11 10 / .55), rgb(11 11 10 / .3) 45%, transparent 70%);
  }
}
.cta h2 { max-width: 14ch; font-size: clamp(2.2rem, 5.5vw, 4.5rem); }
.cta p { max-width: 34rem; color: rgb(237 234 227 / .8); font-size: 1.08rem; }
.cta .btn { margin-top: .5rem; }
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .cta .photo-bg { animation: cta-drift linear both; animation-timeline: --cta; animation-range: cover; }
  }
}
@keyframes cta-drift { from { transform: scale(1.18) translateY(-3%); } to { transform: scale(1.02) translateY(2%); } }

/* ---------- home: the courses ---------- */
/* Built like the loadout select above it: a slab, and on its inset two plates, the
   bench photo and a pressed-in tray with a row per course (name and price, then the
   category and length, and the next date once one is announced). The price reads like
   the loadout's round count. */
.train { box-shadow: var(--slab); }
@media (min-width: 56rem) { .train { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); } }
.train .split-panel-media img { object-position: 50% 30%; }
.train .split-panel-body { justify-content: space-between; gap: 1.1rem; padding: .45rem .45rem clamp(1.1rem, 2.5vw, 1.5rem); }
.train-list { list-style: none; padding: .3rem; border-radius: calc(var(--r-lg) - .45rem); background: var(--bg); box-shadow: var(--press); }
.train-list li + li { border-top: 1px solid var(--line-soft); }
.train-list a {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: baseline; gap: .25rem 1.25rem;
  padding: .75rem 1.05rem; border-radius: calc(var(--r-lg) - .75rem); color: inherit; text-decoration: none;
  transition: background-color .25s var(--ease);
}
@media (hover: hover) { .train-list a:hover { background: rgb(237 234 227 / .05); } }
.train-name { font-weight: 600; }
.train-price {
  display: inline-flex; align-items: center; gap: .5rem;
  font: 700 1.25rem/1 var(--display); font-stretch: 120%; font-variant-numeric: tabular-nums; white-space: nowrap;
}
.train-price::after {
  content: ''; width: .9rem; height: .9rem; background: var(--muted);
  -webkit-mask: var(--i-arrow) center / contain no-repeat; mask: var(--i-arrow) center / contain no-repeat;
}
.train-meta, .train-date { font-size: .85rem; color: var(--muted); }
.train-date { text-align: right; color: var(--text-2); white-space: nowrap; }
.train-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1.25rem 2rem; padding-inline: 1.35rem; }
.train-team { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: 1rem 1.75rem; }

/* ---------- sessions page ---------- */
.jump {
  position: sticky; z-index: 20; top: calc(var(--nav-top) + 4.4rem);
  display: flex; gap: .3rem; width: max-content; max-width: 100%;
  margin: 0 auto 1.25rem; padding: .35rem; overflow-x: auto; scrollbar-width: none;
  border-radius: var(--pill);
  background: rgb(20 20 19 / .78); box-shadow: var(--groove); -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px);
}
.jump::-webkit-scrollbar { display: none; }
.jump a {
  flex: none; display: inline-flex; align-items: baseline; gap: .45rem;
  padding: .5rem .9rem; border-radius: var(--pill);
  color: var(--muted); font-size: .88rem; text-decoration: none; white-space: nowrap;
  transition: background-color .25s, color .25s;
}
.jump a b { color: var(--text); font-weight: 600; }
.jump a:hover { background: rgb(237 234 227 / .07); color: var(--text); }
.jump a.is-active { background: var(--key-ivory); color: rgb(11 11 10 / .7); box-shadow: var(--raise-ivory-sm); }
.jump a.is-active b { color: var(--bg); }

/* The armoury is the loadout screen: on a wide screen the keys stand down the left
   in a groove, the chosen session raised, and its loadout is on the right. With JS
   (main.js) only the chosen session shows; without it they are all listed. */
.jump small { display: none; }
.loadout-grid { display: grid; grid-template-columns: minmax(0, 1fr); }
/* no heading: it carries straight on from the picks, a heading's gap below them */
.section:has(+ .loadout) { padding-bottom: clamp(2rem, 4vw, 3rem); }
@media (min-width: 60rem) {
  .loadout-grid { grid-template-columns: minmax(0, 15.5rem) minmax(0, 1fr); gap: clamp(1.25rem, 2.5vw, 2.5rem); align-items: start; }
  .loadout .jump { flex-direction: column; gap: .2rem; width: auto; margin: 0; padding: .4rem; border-radius: var(--r-lg); }
  .loadout .jump a { align-items: center; justify-content: space-between; gap: 1rem; padding: .65rem .95rem .65rem 1.1rem; white-space: normal; text-wrap: balance; }
  .loadout .jump small { display: block; margin-top: .1rem; font-size: .78rem; color: var(--dim); }
  .loadout .jump a.is-active small { color: rgb(11 11 10 / .55); }
  .loadout .jump b { font-variant-numeric: tabular-nums; }
  .loadout:has(.course) .loadout-grid { grid-template-columns: minmax(0, 19rem) minmax(0, 1fr); }
}
/* The course keys are the home page's loadout keys (.kit-key): a course's name wraps
   to two lines, and a pill round two lines swelled into a capsule with the name
   quieter than its price. So: a rounded key inside the groove's corner, the name in
   ivory at 600, the length under it, the price in the display face like every price.
   With main.js the raised key is one slab (the list's ::before) that slides to the
   course being read, placed from its key (--x, --y, --w, --h); the words are blended
   against it (difference), so they turn dark wherever it is under them. */
@media (min-width: 60rem) {
  .loadout:has(.course) .jump { gap: .15rem; padding: .35rem; }
  .loadout:has(.course) .jump a {
    padding: .7rem 1rem .7rem 1.1rem; border-radius: calc(var(--r-lg) - .35rem);
    color: var(--text); font-size: .95rem; font-weight: 600; line-height: 1.25;
    text-wrap: pretty; /* balance split "Advanced / Work With Rifle" */
  }
  .loadout:has(.course) .jump small { margin-top: .2rem; font-weight: 400; font-size: .78rem; }
  .loadout:has(.course) .jump b { font-family: var(--display); font-stretch: 110%; font-weight: 700; }
  .loadout:has(.course) .jump a.is-active { color: var(--bg); }
  .loadout:has(.course) .jump { --slab-r: calc(var(--r-lg) - .35rem); }
}
.loadout:has(.course) .jump.is-live::before {
  content: ''; position: absolute; top: 0; left: 0; width: var(--w); height: var(--h);
  translate: var(--x) var(--y); border-radius: var(--slab-r, var(--pill)); pointer-events: none;
  background: var(--key-ivory); box-shadow: var(--raise-ivory-sm);
  transition: translate .55s var(--ease), width .55s var(--ease), height .55s var(--ease);
}
.loadout:has(.course) .jump.is-live a { position: relative; mix-blend-mode: difference; }
.loadout:has(.course) .jump.is-live a.is-active { background: none; color: var(--text); box-shadow: none; }
.loadout:has(.course) .jump.is-live a.is-active b { color: var(--text); }
.loadout:has(.course) .jump.is-live small { color: var(--muted); }
/* They stay stuck beside the sheets as you scroll through them. On a short screen they
   drop their length line and tighten, so all eight stay in view: in full they reach
   773px down a 720px screen. */
@media (min-width: 60rem) and (max-height: 50rem) {
  .loadout:has(.course) .jump small { display: none; }
  .loadout:has(.course) .jump a { padding-block: .45rem; }
}

.stack { display: grid; gap: 1rem; }
.loadout .stack { container-type: inline-size; }
.session, .course {
  display: grid; grid-template-columns: minmax(0, 1fr); overflow: hidden; scroll-margin-top: 9.5rem;
  border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--line-soft);
}
.session.is-featured { border-color: rgb(237 234 227 / .32); }
.session-media { position: relative; aspect-ratio: 16 / 10; margin: .45rem; border-radius: calc(var(--r-lg) - .45rem); overflow: hidden; background: #000; }
.session-media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.session-body { display: flex; flex-direction: column; gap: 1.2rem; padding: clamp(1.4rem, 3.5vw, 2.4rem); }
.session-body > p { color: var(--text-2); max-width: 40rem; }
.session h3 { font-size: clamp(1.9rem, 3vw, 2.6rem); }
.session-foot, .course-foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.5rem;
  margin-top: auto; padding-top: 1.25rem; border-top: 1px solid var(--line-soft);
}
:is(.session-foot, .course-foot) .btn { margin-left: auto; }
:is(.session-foot, .course-foot) .muted { order: 1; flex-basis: 100%; margin-top: -.5rem; font-size: .92rem; }
@container (min-width: 32rem) {
  .session-media { aspect-ratio: 2 / 1; }
  .session .case { grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr)); }
}
/* Wide: the photo beside the name and description, then the loadout and the price
   across the full width. A photo beside the whole dossier was a tall sliver that
   cut every landscape shot to a strip; beside the intro it stays landscape. */
@container (min-width: 46rem) {
  .session {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); grid-template-rows: auto 1fr auto auto;
    gap: 1.2rem clamp(1.5rem, 3vw, 2.4rem); padding: .45rem .45rem clamp(1.4rem, 3vw, 2.2rem);
  }
  .session-body { display: contents; }
  .session-media { grid-row: 1 / 3; aspect-ratio: auto; min-height: 16rem; margin: 0; }
  .session-body > * { grid-column: 2; padding-right: clamp(1.4rem, 3vw, 2.2rem); }
  .session-body > :first-child { padding-top: clamp(1.4rem, 3vw, 2.2rem); }
  /* the slots are plates like the photo, on its inset; the price lines up with their text */
  .session-body > :is(.case, .session-foot) { grid-column: 1 / -1; padding-inline: 0; }
  .session-body > .session-foot { padding-inline: .95rem; }
  .session-body > .case { margin-top: .6rem; grid-template-columns: repeat(auto-fill, minmax(10.75rem, 1fr)); }
}
@media (min-width: 60rem) { .session, .course { scroll-margin-top: 1.5rem; } }
/* a session comes in the way a game equips a class: the dossier, then its guns one
   after another */
@media (prefers-reduced-motion: no-preference) {
  .is-tabs .is-visible :is(.session, .course) { animation: equip .45s var(--ease) both; }
  .is-tabs .is-visible .session .case li { animation: equip .4s var(--ease) both; animation-delay: calc(.12s + var(--slot, 0) * 60ms); }
  .is-tabs .is-visible .syllabus li { animation: equip .4s var(--ease) both; animation-delay: calc(.12s + min(var(--slot, 0), 16) * 35ms); }
}
@keyframes equip { from { opacity: 0; translate: 0 .6rem; } }
@media (max-width: 30rem) { :is(.session-foot, .course-foot) .btn { margin-left: 0; width: 100%; } }

/* A gun's artwork as a silhouette in the page's ivory, the way a game draws its
   loadout: the file's transparency is the mask, so artwork must be a cut-out
   (a PNG, WebP or bundled SVG with a transparent background). Every file is a
   300×93 canvas with the gun fitted to it and centred, so the slots line up. */
.art {
  display: block; background: var(--text);
  -webkit-mask: var(--art) left center / contain no-repeat; mask: var(--art) left center / contain no-repeat;
}

/* the loadout: a foam case, one slot pressed in per gun, the round count read
   like a game's ammo counter. The name has the slot's whole width and the counter
   sits beside the gun type under it; a slot too narrow for that (two a row on a
   phone) puts the counter on its own line. Sharing a line with the counter left
   "Dragunov" and "гладкоцевна" 55px on a phone and broke them mid-word. Two a row
   from 352px wide (8rem, Sept 2026: at 8.5rem a 360px phone stood them one a row).
   A 320px phone keeps one a row: in two, Bulgarian's "Снайперова" (89px) would break. */
.case { list-style: none; padding: 0; display: grid; gap: .5rem; grid-template-columns: repeat(auto-fill, minmax(min(8rem, 100%), 1fr)); }
.case li {
  display: grid; align-content: end; gap: .1rem .6rem;
  grid-template: "art art" auto "name name" auto "kind ammo" auto / minmax(0, 1fr) auto;
  container: slot / inline-size;
  padding: .85rem .95rem .8rem; border-radius: var(--r-sm);
  background: var(--bg); box-shadow: var(--press);
}
.case .art { grid-area: art; height: 2.9rem; margin-bottom: .6rem; }
.case-name, .case-kind { overflow-wrap: break-word; }
.case-name { grid-area: name; font-weight: 600; font-size: .95rem; line-height: 1.25; }
.case-kind { grid-area: kind; align-self: start; padding-top: .15rem; font-size: .78rem; line-height: 1.3; color: var(--muted); }
.case-rounds { grid-area: ammo; align-self: end; text-align: right; font: 700 1.55rem/1 var(--display); font-stretch: 125%; font-variant-numeric: tabular-nums; }
.case-rounds small { display: block; margin-top: .25rem; font: 400 .72rem/1.2 var(--body); color: var(--muted); }
@container (max-width: 46rem) { .case li { padding: .75rem .8rem .7rem; } }
/* measured inside the slot's padding: the longest Bulgarian type word (78px), the
   gap and the counter (51px) need 8.75rem */
@container slot (width < 8.75rem) {
  .case-kind { grid-column: 1 / -1; }
  .case-rounds { grid-area: auto; grid-column: 1 / -1; grid-row: 4; margin-top: .4rem; text-align: left; font-size: 1.3rem; }
  .case-rounds small { display: inline; margin: 0 0 0 .3rem; }
}

/* The brief's photographs are black and white, like intel. */
.bw .photo-bg, .bw img { filter: grayscale(1) contrast(1.06); }

/* the hero's facts come in one line after another, after the title, the way the other
   copy under a hero title does (they used to type in, which read as a gimmick) */
.typed { list-style: none; padding: 0; display: grid; gap: .1rem; margin-top: .35rem; font-weight: 500; font-size: 1.02rem; line-height: 1.55; }
.typed li { width: fit-content; }
.typed b { font-family: var(--display); font-stretch: 115%; font-weight: 700; }
@media (prefers-reduced-motion: no-preference) {
  .typed li { animation: rise 1.1s var(--ease) both; animation-delay: calc(440ms + var(--l, 0) * 140ms); }
  .typed li:nth-child(2) { --l: 1; }
  .typed li:nth-child(3) { --l: 2; }
  .typed li:nth-child(4) { --l: 3; }
}


/* The sessions head is the view down the range from the covered line, shipped
   graded dark (highlights held to about half) so the copy holds 3:1 and 4.5:1 with
   the page's usual scrim. On a phone, frame the left shooter's dark back under the
   copy rather than darken the whole photograph. */
@media (max-width: 48rem) {
  .head-group .photo-bg { background-position: 8% center; }
  .head-group .photo-bg::after { background: linear-gradient(to top, rgb(11 11 10 / .9) 0%, rgb(11 11 10 / .55) 60%, rgb(11 11 10 / .1) 85%); }
}

/* the head's two actions, reused in the group CTA */
.head-actions { display: flex; flex-wrap: wrap; gap: .6rem; }
.cta .head-actions .btn { margin-top: 0; }

/* "which one's for your lot?": a situation, then the session it points to.
   The foot is the link, stretched over the card; inline-edit spans sit above it
   so staff can type without jumping down the page. */
.picks { display: grid; gap: .75rem; grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr)); }
.pick {
  position: relative; display: flex; flex-direction: column; gap: .7rem;
  padding: 1.5rem 1.5rem 1.25rem; border-radius: var(--r-lg);
  background: var(--surface); border: 1px solid var(--line-soft); box-shadow: var(--slab);
  transition: border-color .3s var(--ease), background-color .3s var(--ease), translate .4s var(--ease);
}
@media (hover: hover) { .pick:hover { border-color: rgb(237 234 227 / .22); background: var(--surface-2); translate: 0 -3px; } }
.pick-title { font-size: clamp(1.3rem, 1.9vw, 1.6rem); line-height: 1.1; }
/* the session's guns, at their true sizes: a class picked from a loadout screen */
.pick-kit { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .8rem; margin-bottom: .5rem; }
.pick-kit .art { width: 4.2rem; height: 1.3rem; background: var(--text-2); }
.pick-body { color: var(--muted); font-size: .95rem; }
.pick .inline-edit { position: relative; z-index: 1; }
.pick-foot {
  display: flex; align-items: center; gap: .6rem; margin-top: auto; padding-top: 1rem;
  border-top: 1px solid var(--line-soft); color: var(--text); text-decoration: none; font-weight: 500;
}
.pick-foot::before { content: ''; position: absolute; inset: 0; border-radius: inherit; }
.pick-foot b { margin-left: auto; font-family: var(--display); font-stretch: 110%; font-weight: 700; }
.pick-foot::after {
  content: ''; width: 1rem; height: 1rem; flex: none; background: currentColor;
  -webkit-mask: var(--i-arrow) center / contain no-repeat; mask: var(--i-arrow) center / contain no-repeat;
  transition: translate .35s var(--ease);
}
@media (hover: hover) { .pick:hover .pick-foot::after { translate: 3px 0; } }
.pick-foot:focus-visible { outline: none; }
.pick:has(.pick-foot:focus-visible) { outline: 2px solid var(--text); outline-offset: 2px; }

/* Questions, grouped the way a visitor asks them: three columns on a wide screen.
   Each question is a panel whose toggle is a round cap (a plus that becomes a minus),
   and where the browser can animate to auto the answer slides open. */
/* the questions open on a panel: their heading, the four checks and a photo */
.faq-head { margin-bottom: clamp(2rem, 4vw, 3rem); }
.faq-groups { display: grid; gap: 2.25rem 1rem; grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr)); align-items: start; }
.faq-group { display: grid; gap: 1rem; }
.faq-group h3 { font-size: clamp(1.2rem, 1.6vw, 1.4rem); }
.faq { display: grid; gap: .5rem; }
.faq details {
  border-radius: var(--r); background: var(--surface); border: 1px solid var(--line-soft);
  transition: background-color .3s var(--ease), border-color .3s var(--ease);
}
.faq details[open]:not(.is-closing) { background: var(--surface-2); border-color: rgb(237 234 227 / .14); }
.faq summary {
  position: relative; display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: .8rem .8rem .8rem 1.2rem; border-radius: var(--r); cursor: pointer; list-style: none;
  font-weight: 500; line-height: 1.35;
}
.faq summary::-webkit-details-marker { display: none; }
/* the toggle: a round cap (::after), and over it the plus (::before), which spins half
   a turn into a minus as its question opens, and back as it closes */
.faq summary::after {
  content: ''; flex: none; width: 2.1rem; height: 2.1rem; border-radius: 50%;
  background: var(--cap-sheen) var(--cap); box-shadow: var(--cap-up);
  transition: background-color .25s var(--ease), box-shadow .18s var(--ease), transform .18s var(--ease);
}
.faq summary::before {
  --bar: linear-gradient(var(--text) 0 0);
  content: ''; position: absolute; z-index: 1; top: 50%; right: 1.85rem; width: .75rem; height: .75rem;
  translate: 50% -50%; pointer-events: none;
  background: var(--bar) center / .75rem 1.5px no-repeat, var(--bar) center / 1.5px .75rem no-repeat;
  transition: rotate .5s var(--ease), background-size .35s var(--ease), translate .18s var(--ease);
}
.faq details[open]:not(.is-closing) summary::before { rotate: 180deg; background-size: .75rem 1.5px, 1.5px 0; }
@media (hover: hover) {
  .faq summary:hover::after { background-color: var(--cap-hover); box-shadow: var(--cap-lift); transform: translateY(-1px); }
  .faq summary:hover::before { translate: 50% calc(-50% - 1px); }
}
.faq summary:active::after { box-shadow: var(--cap-down); transform: translateY(1px); }
.faq summary:active::before { translate: 50% calc(-50% + 1px); }
.faq-a { display: grid; gap: .8rem; padding: 0 1.2rem 1.2rem; }
.faq-a p { color: var(--text-2); font-size: .95rem; max-width: 38rem; }
/* main.js slides each panel open and shut. The answer rises in a beat behind the
   height, a paragraph at a time, and goes first when it closes. */
@media (prefers-reduced-motion: no-preference) {
  .js .faq details[open]:not(.is-closing) .faq-a > * { animation: faq-in .6s var(--ease) both; animation-delay: .08s; }
  .js .faq details[open]:not(.is-closing) .faq-a > :nth-child(2) { animation-delay: .16s; }
  .js .faq details[open]:not(.is-closing) .faq-a > :nth-child(n+3) { animation-delay: .24s; }
  .js .faq details.is-closing .faq-a > * { opacity: 0; translate: 0 -.3rem; transition: opacity .15s, translate .2s; }
}
@keyframes faq-in { from { opacity: 0; translate: 0 .7rem; } }

.help-panel {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1rem 2rem;
  padding: clamp(1.5rem, 4vw, 2.5rem); border-radius: var(--r-lg);
  background: var(--surface-2); border: 1px solid var(--line-soft);
}
.help-panel h2 { font-size: clamp(1.5rem, 3vw, 2.2rem); }
.help-panel p { color: var(--muted); margin-top: .4rem; }

/* ---------- courses: the reel ----------
   The drone edit, decoded frame by frame onto a canvas as the page scrolls
   (main.js), with each course surfacing over the footage in turn. Until main.js
   adds .is-on the stage is a plain .page-head. On, the section grows four fifths of a
   screen per course and the stage pins edge to edge: the film is the page here, so
   it leaves the frame motif, at the client's request (Sept 2026). main.js sets --in
   and --out (0–1) on every caption; everything below derives from those two
   numbers, so scrolling back plays it all backwards. */
.reel.is-on { height: calc((1 + var(--chapters) * .8) * 100svh); }
.reel.is-on .reel-stage {
  position: sticky; top: 0; height: 100svh; min-height: 0; margin: 0; border-radius: 0;
  grid-template-areas: 'copy'; align-content: stretch;
  padding: 0 var(--gutter) clamp(4.75rem, 9svh, 5.75rem); background: var(--bg); /* clear of .reel-next */
  /* Leaving: past the last course main.js takes --leave from 0 to 1, and the film
     draws in to the rounded frame every other head on the site sits in, so it
     scrolls away as one of them and the page below carries straight on. */
  clip-path: inset(calc(var(--leave, 0) * var(--frame)) round calc(var(--leave, 0) * var(--r-lg)));
}
/* Under 56rem the nav stands over the page, not the film: the stage is a frame below
   it that fills the rest of the screen, like the home band's. The section's top padding
   puts it there from the start, where it pins; main.js reads that place and the stage's
   height for the film's travel. Framed from the start, it has nothing to draw in to on
   the way out. */
@media (max-width: 55.99rem) {
  .reel.is-on { --reel-top: var(--below-nav); padding-top: var(--reel-top); }
  .reel.is-on .reel-stage {
    top: var(--reel-top); height: calc(100svh - var(--reel-top) - var(--frame));
    margin-inline: var(--frame); border-radius: var(--r-lg); clip-path: none; padding-inline: var(--frame-pad);
  }
}
.reel.is-on .reel-index { opacity: calc(1 - var(--leave, 0)); }
/* The film fades up from black as its first frame decodes. The poster is the head
   for phones and no JS, and comes back if the browser cannot decode the film. */
.reel.is-on .photo-bg { display: none; }
.reel.is-on.is-broken .photo-bg { display: block; }
.reel-canvas { position: absolute; inset: 0; z-index: -2; width: 100%; height: 100%; opacity: 0; transition: opacity 1.2s ease; }
.reel-canvas.is-drawn { opacity: 1; }
/* One still scrim: the whole film dimmed evenly, a shade under the nav and a floor
   along the bottom. The client asked for the dark filter over the whole film (Sept
   2026), the exception to "never darken a whole photograph". It replaced a pool of
   shade that slid to whichever corner the caption was in, which they found a weird
   changing effect. */
.reel.is-on .reel-stage::before {
  content: ''; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background:
    linear-gradient(rgb(11 11 10 / .5), transparent 18%),
    linear-gradient(to top, rgb(11 11 10 / .5), transparent 40%),
    rgb(11 11 10 / .4);
}
/* On a phone the film fills the top of the frame and fades into black, and the title
   and captions sit below it on the black. Filling the whole upright frame, it showed
   a third of the drone shot blown up 1.7x, a grey gravel roof under the filter with the
   text crammed over it (Sept 2026); in 60% of the frame it shows about half, sharp. */
@media (max-width: 55.99rem) {
  .reel.is-on :is(.reel-canvas, .photo-bg) { bottom: auto; height: 60%; }
  .reel.is-on .reel-stage::before { background: linear-gradient(rgb(11 11 10 / .4), rgb(11 11 10 / .4) 36%, var(--bg) 60%); }
}
/* the title and lead sit in a wrapper, so they need the page head's gap of their own */
.reel-intro { display: grid; gap: 1.25rem; }
.reel.is-on :is(.reel-intro, .reel-ch) { grid-area: copy; align-self: end; max-width: 44rem; }
/* captions keep to their side and leave the middle of the frame, where the
   operator usually is, to the footage */
.reel.is-on .reel-ch { max-width: min(31rem, 100%); }
.reel.is-on .reel-intro > * { opacity: calc(1 - var(--out, 0)); translate: 0 calc(var(--out, 0) * -2.5rem); }

.reel-ch { --in: 0; --out: 0; }
.reel-ch:nth-child(even of .reel-ch) { justify-self: end; }
.reel-ch.is-off { visibility: hidden; }
/* each part arrives a beat after the one above it (--k) and all leave together */
.reel-ch > * {
  --i: clamp(0, var(--in) * 1.6 - var(--k, 0) * .3, 1);
  opacity: calc(var(--i) * (1 - var(--out)));
  translate: 0 calc((1 - var(--i)) * 2.5rem - var(--out) * 2rem);
}
.reel-ch > :nth-child(2) { --k: 1; }
.reel-ch > :nth-child(3) { --k: 1.5; }
.reel-ch > :nth-child(4) { --k: 2; }
/* the name rises out of its own mask, like the home hero's lines. Not an h2: the
   course cards below carry the headings, and the outline should list each once. */
.reel-name {
  font-size: clamp(2.2rem, 4.4vw, 4.4rem); line-height: .92;
  overflow: hidden; padding-bottom: .08em; margin-bottom: -.08em; opacity: 1; translate: none;
}
.reel-name > span { display: block; translate: 0 calc((1 - var(--i)) * 105% - var(--out) * 105%); }
.reel-facts { margin-top: 1.1rem; color: rgb(237 234 227 / .8); font-size: clamp(1rem, 1.2vw, 1.1rem); }
.reel-ch .price { margin-top: .9rem; }
.reel-actions { display: flex; flex-wrap: wrap; gap: .6rem; margin-top: 1.5rem; }

/* where you are in the film; a click jumps to that course */
.reel-index {
  position: absolute; z-index: 1; top: 50%; right: clamp(.5rem, 1.5vw, 1.5rem); translate: 0 -50%;
  display: grid; list-style: none; padding: 0;
}
.reel-index a { display: flex; justify-content: flex-end; align-items: center; width: 2.75rem; height: 1.5rem; }
.reel-index a::before {
  content: ''; width: .9rem; height: 2px; border-radius: 2px; background: rgb(237 234 227 / .35);
  transition: width .5s var(--ease), background-color .5s var(--ease);
}
.reel-index a:hover::before { background: rgb(237 234 227 / .75); }
.reel-index a[aria-current]::before { width: 2rem; background: var(--text); }
@media (max-width: 64rem) { .reel-index { display: none; } }

/* The call to scroll and the button that scrolls through, in one of the site's own
   dark caps (.btn-ghost), at the bottom centre. At the top of the film it is a pill
   that says "Scroll through the courses", its arrow nudging; once the film moves the
   words fold away into a round cap. The arrow points the way you are going and spins
   round when you turn back; one press moves one course that way, as one push of the
   wheel does (past the last course, on to the course list), and on each move the
   arrow (an <i>, so the script can animate it everywhere) slips out of the cap and back
   in (main.js). A round cap with the words beside
   it looked bolted on (24 Sept 2026). The stage's bottom padding keeps the captions
   clear of it. */
.reel.is-on .reel-next {
  position: absolute; z-index: 1; left: 50%; bottom: clamp(1rem, 2.5svh, 1.75rem); translate: -50% 0;
  gap: 0; min-height: 0; height: 2.85rem; padding: 0 calc(.85rem - 1px); overflow: hidden;
  opacity: calc(1 - var(--leave, 0));
  transition: background-color .25s var(--ease), box-shadow .18s var(--ease), transform .18s var(--ease),
              padding .6s var(--ease);
}
.reel.is-top .reel-next { padding-inline: 1.3rem 1.05rem; transition-duration: .25s, .18s, .18s, .7s; }
.reel-next > span {
  max-width: 0; overflow: hidden; white-space: nowrap; opacity: 0;
  transition: max-width .6s var(--ease), margin .6s var(--ease), opacity .25s var(--ease);
}
.reel.is-top .reel-next > span {
  max-width: 16rem; margin-right: .65rem; opacity: 1;
  transition: max-width .7s var(--ease), margin .7s var(--ease), opacity .5s var(--ease) .2s;
}
.reel-next i {
  flex: none; width: 1.15rem; height: 1.15rem; background: currentColor; rotate: 90deg;
  -webkit-mask: var(--i-arrow) center / contain no-repeat; mask: var(--i-arrow) center / contain no-repeat;
  transition: rotate .6s cubic-bezier(.34, 1.45, .64, 1);
}
.reel[data-way="up"] .reel-next i { rotate: -90deg; }
@media (prefers-reduced-motion: no-preference) {
  .reel.is-top .reel-next i { animation: nudge 2.4s var(--ease-io) 1.2s infinite; }
}
@keyframes nudge { 0%, 50%, 100% { translate: 0 0; } 25% { translate: 0 .28rem; } }

/* ---------- courses ----------
   The syllabus: the armoury (.loadout, main.js) with a course sheet for the dossier.
   Its topics run down the columns in the order they are taught, numbered, in a
   pressed-in tray like the loadout's guns. */
.course { --in: clamp(1.4rem, 3.5vw, 2.4rem); gap: 1.2rem; padding: var(--in); }
.course-head { display: grid; align-items: start; gap: 1.1rem 2rem; }
@container (min-width: 40rem) { .course-head { grid-template-columns: minmax(0, 1fr) auto; } }
.course-head .muted { margin-top: .4rem; }
.course h2 { font-size: clamp(1.9rem, 3vw, 2.6rem); }
.course > p { color: var(--text-2); max-width: 44rem; }
.course h3 { font-family: var(--body); font-stretch: 100%; font-size: .95rem; font-weight: 600; color: var(--muted); letter-spacing: 0; margin-top: .4rem; }
.syllabus {
  list-style: none; counter-reset: topic; columns: 3 13.5rem; column-gap: 2.5rem; column-rule: 1px solid var(--line-soft);
  margin-top: -.4rem; padding: .7rem 1.25rem; border-radius: var(--r); background: var(--bg); box-shadow: var(--press);
}
.syllabus li {
  counter-increment: topic; break-inside: avoid;
  display: grid; grid-template-columns: 2.3rem minmax(0, 1fr); padding: .5rem 0;
  font-size: .95rem; line-height: 1.4; color: var(--text-2);
}
.syllabus li::before {
  content: counter(topic, decimal-leading-zero);
  font: 700 .78rem/1.8 var(--display); font-stretch: 125%; font-variant-numeric: tabular-nums; color: var(--dim);
}
/* a phone: the tray is a plate on the sheet's inset, like the loadout's slots, so
   the topics keep their width */
@container (max-width: 30rem) {
  .syllabus { margin-inline: calc(.45rem - var(--in)); padding-inline: .9rem; }
  .syllabus li { grid-template-columns: 2rem minmax(0, 1fr); }
}

.person { display: flex; align-items: center; gap: .8rem; }
.person img { width: 3.1rem; height: 3.1rem; flex: none; border-radius: 50%; object-fit: cover; object-position: top; }
.person b { display: block; font-weight: 600; line-height: 1.25; }
.person span { display: block; color: var(--muted); font-size: .85rem; line-height: 1.3; }

/* ---------- about ---------- */
.split { display: grid; grid-template-columns: minmax(0, 1fr); gap: clamp(2rem, 5vw, 4.5rem); align-items: center; }
@media (min-width: 56rem) { .split { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); } }
.split-img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; border-radius: var(--r-lg); }
.prose { display: grid; gap: 1.1rem; }
.prose p { color: var(--text-2); }

/* ---------- about ----------
   How the line runs, beside the range's posted rules, then the instructors, one
   row each with the photo on alternating sides. Numbered steps on hairlines, not
   cards: they are a procedure, read top to bottom. */
/* The head's photo is bright gravel and trees round two figures, and the heading
   runs three lines up its lower half (four in Bulgarian). Measured (Sept 2026) at
   320-1920 wide in both languages: at least 4.1:1 against the brightest pixel
   behind each line, the Bulgarian heading at 1280 being the worst case. The faces
   at the top stay nearly clear. Team building's head (white shirts) shares its scrim. */
.about-head .photo-bg { background-position: 50% 30%; }
/* a phone sees a narrow slice: keep the instructor's face and his hand on the grip */
@media (max-width: 40rem) { .about-head .photo-bg { background-position: 40% 30%; } }
.about-head .photo-bg::after, .team-head .photo-bg::after {
  background:
    linear-gradient(to top, rgb(11 11 10 / .9) 0%, rgb(11 11 10 / .8) 42%, rgb(11 11 10 / .55) 64%, rgb(11 11 10 / .2) 86%, transparent 100%),
    linear-gradient(90deg, rgb(11 11 10 / .48), rgb(11 11 10 / .22) 57%, transparent 82%);
}
/* on a phone the team head's copy climbs nearly to the top of the frame, over white shirts */
@media (max-width: 40rem) {
  .team-head .photo-bg::after { background: linear-gradient(to top, rgb(11 11 10 / .9) 0%, rgb(11 11 10 / .8) 55%, rgb(11 11 10 / .6) 100%); }
}
.about-line { display: grid; grid-template-columns: minmax(0, 1fr); gap: clamp(2rem, 5vw, 4.5rem); align-items: center; }
@media (min-width: 56rem) { .about-line { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); } }
.about-line h2 { margin-bottom: clamp(1.5rem, 3vw, 2.25rem); }
.about-line-photo { margin: 0; aspect-ratio: 4 / 5; overflow: hidden; border-radius: var(--r-lg); background: var(--surface); }
.about-line-photo img { width: 100%; height: 100%; object-fit: cover; }

.steps { list-style: none; padding: 0; counter-reset: step; }
.steps li {
  counter-increment: step; display: grid; grid-template-columns: 3rem minmax(0, 1fr); column-gap: 1rem;
  padding: 1.15rem 0; border-top: 1px solid var(--line);
}
.steps li:last-child { border-bottom: 1px solid var(--line); }
.steps li::before { content: counter(step, decimal-leading-zero); grid-row: span 2; font: 700 1.05rem/1.45 var(--display); color: var(--dim); }
.steps h3 { margin-bottom: .35rem; }
.steps p { color: var(--muted); }

.team { display: grid; gap: clamp(3rem, 7vw, 5.5rem); }
.member { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.5rem clamp(2rem, 5vw, 4.5rem); align-items: center; }
@media (min-width: 56rem) {
  .member { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); }
  .member:nth-child(even) { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); }
  .member:nth-child(even) .member-photo { order: 2; }
}
.member-photo { aspect-ratio: 4 / 5; overflow: hidden; border-radius: var(--r-lg); background: var(--surface); }
.member-photo img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 25%; }
.member h3 { font-size: clamp(1.7rem, 3vw, 2.5rem); }
.member-role { margin-top: .5rem; color: var(--muted); }
.member-bio { margin-top: 1.25rem; max-width: 38rem; color: var(--text-2); }
/* the qualifications fold away: a wall of badges read as clutter */
.member-quals { margin-top: 1.5rem; max-width: 38rem; border-top: 1px solid var(--line); }
.member-quals summary {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  padding: .9rem 0; cursor: pointer; list-style: none; color: var(--text); font-weight: 500;
}
.member-quals summary::-webkit-details-marker { display: none; }
.member-quals summary::after { content: ''; flex: none; width: 1.1rem; height: 1.1rem; background: var(--i-chevron) center / contain no-repeat; transition: rotate .3s var(--ease); }
.member-quals[open] summary::after { rotate: 180deg; }
.member-quals ul { list-style: none; padding: 0 0 .5rem; columns: 2 13rem; column-gap: 2rem; color: var(--muted); font-size: .92rem; }
.member-quals li { break-inside: avoid; padding: .45rem 0; border-top: 1px solid var(--line-soft); }
@supports (interpolate-size: allow-keywords) {
  .member-quals { interpolate-size: allow-keywords; }
  .member-quals::details-content { block-size: 0; overflow: clip; transition: block-size .4s var(--ease), content-visibility .4s allow-discrete; }
  .member-quals[open]::details-content { block-size: auto; }
}

/* ---------- gallery ----------
   Justified rows: each figure grows in proportion to its photo's shape (--ar), so a
   row fills the column at one height and no photo is cropped. --row is the height a
   row aims for, and the ::after filler stops the last row stretching to fill. The
   grow factors are scaled by 100: a line whose factors sum below 1 hands out only
   that fraction of its free space, which left a lone portrait short of the edge. */
.photos { --row: clamp(10rem, 22vw, 19rem); display: flex; flex-wrap: wrap; align-items: flex-start; gap: .75rem; }
.photos::after { content: ''; flex: 1000000 1 0; }
.photos figure {
  flex-grow: calc(var(--ar) * 100); flex-shrink: 1; flex-basis: calc(var(--ar) * var(--row));
  aspect-ratio: var(--ar); margin: 0; overflow: hidden; border-radius: var(--r); background: var(--surface);
}
.photos button { display: block; width: 100%; height: 100%; padding: 0; border: 0; background: none; cursor: zoom-in; }
.photos img { width: 100%; height: 100%; object-fit: cover; transition: transform 1.2s var(--ease); }
@media (hover: hover) { .photos figure:hover img { transform: scale(1.03); } }

.gal-end {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 1.25rem 2rem;
  padding-top: clamp(1.75rem, 4vw, 3rem); border-top: 1px solid var(--line);
}

/* The lightbox pages through the photos: the arrow buttons, the arrow keys or a
   swipe (main.js). pan-y leaves a sideways swipe to the script. */
.lightbox {
  width: 100%; height: 100%; max-width: none; max-height: none; margin: 0; padding: var(--frame);
  border: 0; background: rgb(8 9 8 / .94); color: var(--text); touch-action: pan-y pinch-zoom;
  opacity: 0; transition: opacity .35s var(--ease), overlay .35s allow-discrete, display .35s allow-discrete;
}
.lightbox[open] { display: grid; place-items: center; opacity: 1; }
@starting-style { .lightbox[open] { opacity: 0; } }
.lightbox::backdrop { background: transparent; }
.lightbox figure { display: grid; justify-items: center; gap: .8rem; margin: 0; }
.lightbox img {
  max-width: min(100%, calc(100vw - 2 * var(--frame) - 9rem)); max-height: calc(100svh - 2 * var(--frame) - 3.5rem);
  border-radius: var(--r); object-fit: contain; transition: scale .5s var(--ease);
}
@starting-style { .lightbox[open] img { scale: .94; } }
.lightbox figcaption { display: flex; flex-wrap: wrap; justify-content: center; gap: .25rem .75rem; color: var(--text-2); font-size: .92rem; text-align: center; }
.lightbox-count { color: var(--dim); font-variant-numeric: tabular-nums; }
/* the close button's method="dialog" form must not become a second grid row */
.lightbox form { display: contents; }
.lightbox-close { position: fixed; top: calc(var(--frame) + .75rem); right: calc(var(--frame) + .75rem); }
/* It closes faster than it opens. With view transitions (main.js) the photo grows
   out of its tile in the grid and goes back to it: the tiles are the photos' own
   shapes, so nothing distorts. The nav loses its own transition name meanwhile, or
   it would be drawn over the dark ground until the end. */
.lightbox:not([open]) { transition-duration: .2s; }
html.lb-vt .nav-bar { view-transition-name: none; }
html.lb-vt .lightbox, html.lb-vt .lightbox img { transition: none; }
html.lb-vt::view-transition-old(root) { animation: .3s var(--ease) both vt-out; }
html.lb-vt::view-transition-new(root) { animation: .3s var(--ease) both vt-fade; }
::view-transition-group(lb-photo) { animation-duration: .5s; animation-timing-function: var(--ease); }
::view-transition-old(lb-photo), ::view-transition-new(lb-photo) { animation-duration: .3s; }
@keyframes vt-fade { from { opacity: 0; } }
.lightbox-step { position: fixed; top: 50%; left: calc(var(--frame) + .75rem); translate: 0 -50%; }
.lightbox-step[data-dir="1"] { left: auto; right: calc(var(--frame) + .75rem); }
/* a phone has no room beside the photo: the arrows go under it */
@media (max-width: 40rem) {
  .lightbox img { max-width: 100%; max-height: calc(100svh - 2 * var(--frame) - 9rem); }
  .lightbox-step { top: auto; bottom: calc(var(--frame) + .75rem); translate: none; }
}

/* ---------- forms ---------- */
label { display: block; margin: 1rem 0 .4rem; font-size: .88rem; font-weight: 500; color: var(--text-2); }
input, select, textarea {
  width: 100%; min-height: 3rem; padding: .7rem 1rem;
  font: inherit; font-size: 1rem; color: var(--text);
  background: var(--bg); border: 1px solid var(--line); border-radius: var(--r-sm);
  transition: border-color .2s, background-color .2s;
}
textarea { min-height: 7.5rem; resize: vertical; line-height: 1.5; }
input::placeholder, textarea::placeholder { color: var(--dim); }
input:hover, select:hover, textarea:hover { border-color: #3A3935; }
input:focus, select:focus, textarea:focus { outline: none; border-color: rgb(237 234 227 / .7); }
input, select, textarea, .stepper { box-shadow: var(--press); }
input[type=checkbox], input[type=radio], .stepper input { box-shadow: none; }
select {
  appearance: none; -webkit-appearance: none; cursor: pointer; padding-right: 2.75rem;
  background: var(--bg) var(--i-chevron) no-repeat right .9rem center / 1.1rem;
}
select[aria-expanded="true"] { border-color: rgb(237 234 227 / .7); }
/* A select's list (static/js/select.js): a slab under the field, its rows keys. The row
   under the pointer or the arrow keys is raised; the chosen one is the ivory key, like
   every selected state on the site. */
.select-list {
  inset: auto; margin: 0; padding: .35rem;
  max-width: min(28rem, calc(100vw - 1rem));
  overflow-y: auto; overscroll-behavior: contain;
  font-family: var(--body); line-height: 1.35; color: var(--text-2);
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-sm);
  box-shadow: var(--slab);
  scrollbar-width: thin; scrollbar-color: var(--line) transparent;
  transform-origin: top; opacity: 1; transform: none;
  transition: opacity .12s var(--ease), transform .12s var(--ease), display .12s allow-discrete, overlay .12s allow-discrete;
}
.select-list.is-up { transform-origin: bottom; }
.select-list:popover-open { transition-duration: .18s; }
.select-list:not(:popover-open) { opacity: 0; transform: scale(.98); }
@starting-style { .select-list:popover-open { opacity: 0; transform: translateY(-.35rem) scale(.97); } }
@starting-style { .select-list.is-up:popover-open { transform: translateY(.35rem) scale(.97); } }
.select-list:focus { outline: none; }
.select-list [role=option] {
  padding: .6rem .85rem; border-radius: calc(var(--r-sm) - .35rem); cursor: pointer;
  transition: background-color .12s, color .12s;
}
.select-list .is-active { color: var(--text); background: var(--key); box-shadow: var(--raise-sm); }
.select-list [aria-selected="true"] { color: var(--accent-ink); background: var(--key-ivory); box-shadow: var(--raise-ivory-sm); font-weight: 600; }
.select-list [aria-disabled="true"] { color: var(--dim); cursor: default; }
input[type=radio] { width: 1.15rem; height: 1.15rem; min-height: 0; padding: 0; accent-color: var(--accent); }
/* A tick turns the sight on. The reticle's red is the one hue outside the dashboard pills,
   at the owner's request (Sept 2026). The edit bar's switch keeps its own look. */
input[type=checkbox]:not([role=switch]) {
  appearance: none; flex: none; width: 1.85rem; height: 2.25rem; min-height: 0; margin: 0; padding: 0;
  border: 0; border-radius: 4px; background: var(--i-sight) center / contain no-repeat; cursor: pointer;
  transition: background-image .12s, filter .15s;
}
input[type=checkbox]:not([role=switch]):checked { background-image: var(--i-sight-on); }
@media (hover: hover) { input[type=checkbox]:not([role=switch]):hover { filter: brightness(1.25); } }
input[type=checkbox]:not([role=switch]):focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (forced-colors: active) { input[type=checkbox]:not([role=switch]) { appearance: auto; } }
input[type=number] { font-variant-numeric: tabular-nums; }
.field-error { color: var(--danger); font-size: .86rem; margin-top: .35rem; }
.form-errors, .form-success {
  padding: .9rem 1.1rem; border-radius: var(--r-sm); margin-bottom: 1.25rem; font-size: .95rem;
}
.form-errors { border: 1px solid rgb(217 119 111 / .4); background: rgb(217 119 111 / .08); color: #E6A39C; }
.form-errors ul { margin: 0; padding-left: 1.1rem; }
.form-success { border: 1px solid rgb(141 191 157 / .35); background: rgb(141 191 157 / .08); color: var(--text); }
.form-2col { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr)); gap: 0 1rem; }
.fine { font-size: .8rem; line-height: 1.55; color: var(--dim); }
.fine a { color: var(--muted); }

/* ---------- booking ----------
   A short path, a step at a time (main.js). The date, and a session's time, come first:
   until they are picked the steps after them (data-after) are folded to a title and a
   note, and they unfold once. Each step's number sits in a groove: raised while it is
   the one to do, an ivory key with a tick once it's done. The checklist beside the Pay
   button (.todo) is what's left. All of it only with JS (.js): without, nothing folds. */
.book { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1rem; align-items: start; }
@media (min-width: 62rem) { .book { grid-template-columns: minmax(0, 1fr) minmax(19rem, 23rem); gap: 1.25rem; } }
.book-steps { display: grid; gap: 1rem; }
.step-card {
  padding: clamp(1.25rem, 3.5vw, 2.25rem); border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--line-soft); box-shadow: var(--slab);
  transition: background-color .6s var(--ease), box-shadow .6s var(--ease), border-color .6s var(--ease);
}
.step-title { display: flex; align-items: center; gap: .75rem; font-size: clamp(1.2rem, 2vw, 1.4rem); margin-bottom: 1.25rem; transition: color .4s var(--ease); }
.step-no {
  position: relative; display: grid; place-items: center; flex: none; width: 2.1rem; height: 2.1rem; border-radius: 50%;
  background: rgb(0 0 0 / .22); box-shadow: var(--groove); color: var(--accent); font-size: .95rem;
  transition: color .25s, box-shadow .35s var(--ease);
}
/* a done step's tick, and a done item's in the checklist, wipes in from the left */
.step-no::after, .todo button::after {
  content: ''; position: absolute; background: var(--accent-ink);
  -webkit-mask: var(--i-check) center / contain no-repeat; mask: var(--i-check) center / contain no-repeat;
  clip-path: inset(0 100% 0 0);
}
@media (prefers-reduced-motion: no-preference) {
  .step-no::after, .todo button::after { transition: clip-path .45s var(--ease); }
  .js .step-card.is-done .step-no::after, .todo .is-done button::after { transition-delay: .12s; }
}
.step-no::after { inset: 0; width: 1rem; height: 1rem; margin: auto; }
.js .step-card.is-current { border-color: rgb(237 234 227 / .13); }
.js .step-card.is-current .step-no { background: var(--key); box-shadow: var(--raise-sm); color: var(--text); }
.js .step-card.is-done .step-no { background: var(--key-ivory); box-shadow: var(--raise-ivory-sm); color: transparent; }
.js .step-card.is-done .step-no::after { clip-path: inset(0); }
.step-card label:first-of-type { margin-top: 0; }
.step-inner > label:first-of-type { margin-top: 1rem; }  /* the email, under the name and phone */
/* stacked on a phone, and the company's rows: a field's label clear of the one above */
.step-inner .form-2col { row-gap: 1rem; }
.step-hint { color: var(--muted); font-size: .88rem; margin-top: .9rem; }
.stepper ~ .step-hint { margin-top: .55rem; }
/* folded: the title, dimmed, and what opens it */
.step-wait { display: none; margin: .45rem 0 0 2.85rem; color: var(--dim); font-size: .88rem; }
.js .step-card.is-locked { background-color: rgb(20 20 19 / .45); box-shadow: none; }
.js .step-card.is-locked .step-title { color: var(--muted); }
.js .step-card.is-locked .step-no { color: var(--dim); }
.js .step-card.is-locked .step-wait { display: block; }
[data-after] .step-title { margin-bottom: 0; }
.step-body { display: grid; grid-template-rows: 1fr; }
/* clips the fields while the step unfolds; the margin leaves their focus rings room */
.step-inner { min-height: 0; overflow: hidden; margin: 0 -6px -6px; padding: 1.25rem 6px 6px; }
.js .step-card.is-locked .step-body { grid-template-rows: 0fr; visibility: hidden; }
@media (prefers-reduced-motion: no-preference) {
  .step-body { transition: grid-template-rows .75s var(--ease); }
  /* as it opens, its fields rise in one after another (--k, from main.js) */
  .step-card.is-opening .step-inner > * { animation: step-in .7s var(--ease) both; animation-delay: calc(var(--k, 0) * 70ms + 180ms); }
  .js .step-card.is-done .step-no { animation: key-in .5s var(--ease); }
  .book.is-ready .summary .btn-arrow::after { animation: arrow-go .7s var(--ease) .1s 2; }
}
@keyframes step-in { from { opacity: 0; translate: 0 1rem; } }
@keyframes key-in { from { scale: .6; } }
@keyframes arrow-go { 50% { translate: 5px 0; } }
/* a field the visitor still has to fill in; the server marks its own the same way */
.book [aria-invalid="true"]:not(:focus) { border-color: rgb(217 119 111 / .6); }

#calendar { user-select: none; }
.date-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.75rem 2.5rem; align-items: start; }
@media (min-width: 48rem) { .date-grid { grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); } }
.slots-empty {
  display: grid; place-items: center; min-height: 12rem; padding: 1.5rem; text-align: center;
  border: 1px dashed var(--line); border-radius: var(--r); color: var(--dim); font-size: .92rem;
}
#slots:not([hidden]) ~ .slots-empty { display: none; }
@media (max-width: 47.99rem) { .slots-empty { display: none; } }
.cal-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: .75rem; }
.cal-title { font-family: var(--display); font-weight: 700; font-stretch: 108%; font-size: 1.1rem; text-transform: capitalize; }
.cal-nav {
  display: grid; place-items: center; width: 2.5rem; height: 2.5rem; border-radius: 50%;
  border: 0; color: var(--text); cursor: pointer; text-decoration: none;
  transition: border-color .2s, background-color .2s;
}
.cal-nav svg { width: 1.1rem; height: 1.1rem; }
.cal-nav:disabled { opacity: .3; cursor: default; box-shadow: none; }
.cal-dows, .cal-grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: .3rem; }
.cal-dows { margin-bottom: .3rem; }
.cal-dow { padding: .2rem 0 .45rem; text-align: center; font-size: .74rem; color: var(--dim); text-transform: capitalize; }
.cal-day {
  aspect-ratio: 1; border: 1px solid transparent; border-radius: var(--r-sm);
  background: var(--cap-sheen) var(--cap); box-shadow: var(--cap-up); color: var(--text);
  font: 500 .95rem/1 var(--body); font-variant-numeric: tabular-nums; cursor: pointer;
  transition: background-color .2s, color .2s, box-shadow .18s var(--ease), transform .18s var(--ease);
}
@media (hover: hover) { .cal-day:hover:not(:disabled, .is-selected) { background-color: var(--cap-hover); box-shadow: var(--cap-lift); transform: translateY(-1px); } }
.cal-day:active:not(:disabled) { box-shadow: var(--cap-down); transform: translateY(1px); }
.cal-day:disabled { background: none; box-shadow: none; color: #474641; cursor: default; }
.cal-day.is-course-date { border-color: rgb(237 234 227 / .55); color: var(--accent-hi); font-weight: 600; }
.cal-day.is-selected { background: var(--cap-ivory-sheen) var(--cap-ivory); color: var(--accent-ink); font-weight: 700; box-shadow: var(--cap-ivory-up); }
.cal-legend { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1.1rem; margin-top: .8rem; font-size: .82rem; color: var(--muted); }
.dot { display: inline-block; width: .6rem; height: .6rem; margin-right: .35rem; border-radius: 50%; vertical-align: baseline; }
.dot-free { background: rgb(237 234 227 / .3); }
.dot-course { background: var(--accent); }
.dot-blocked { background: #3A3935; }

#slots { margin: 0; }
.slots-label { font-weight: 600; margin-bottom: .7rem; }
.slot-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr)); gap: .5rem; }
.slot {
  padding: .7rem .9rem; text-align: left; cursor: pointer;
  border: 0; border-radius: var(--r-sm); background: var(--cap-sheen) var(--cap); color: var(--text);
  box-shadow: var(--cap-up);
  font: 600 .95rem/1.3 var(--body); font-variant-numeric: tabular-nums;
  transition: background-color .2s, color .2s, box-shadow .18s var(--ease), transform .18s var(--ease);
}
@media (hover: hover) { .slot:hover:not(:disabled, .is-selected) { background-color: var(--cap-hover); box-shadow: var(--cap-lift); transform: translateY(-1px); } }
.slot:active:not(:disabled) { box-shadow: var(--cap-down); transform: translateY(1px); }
.slot:disabled { opacity: .38; cursor: default; text-decoration: line-through; background: var(--bg); box-shadow: none; }
.slot.is-selected { background: var(--cap-ivory-sheen) var(--cap-ivory); color: var(--accent-ink); box-shadow: var(--cap-ivory-up); }
/* inline-block so a disabled slot's line-through doesn't strike the sub-line */
.slot-left { display: inline-block; width: 100%; margin-top: .15rem; font-size: .78rem; font-weight: 400; color: var(--muted); }
.slot.is-selected .slot-left { color: rgb(11 11 10 / .6); }

.stepper {
  display: inline-grid; grid-template-columns: 3rem 4rem 3rem; overflow: hidden;
  border: 1px solid var(--line); border-radius: var(--pill); background: var(--bg);
  transition: border-color .2s;
}
.stepper:focus-within { border-color: rgb(237 234 227 / .7); }
.stepper input {
  min-height: 3rem; padding: 0; border: 0; border-radius: 0; background: none;
  text-align: center; font-weight: 600; -moz-appearance: textfield; appearance: textfield;
}
.stepper input::-webkit-inner-spin-button, .stepper input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.stepper button { border: 0; background: none; color: var(--text); font-size: 1.3rem; line-height: 1; cursor: pointer; transition: background-color .2s; }
.stepper button:hover { background: rgb(237 234 227 / .08); }
.stepper button[aria-disabled="true"] { background: none; color: var(--dim); }
/* Everyone's names (book.html): a field each, numbered in a groove that turns to an ivory
   key once the name is in, like a step that's done. main.js adds and removes them. */
.names-title { margin: 1rem 0 .4rem; color: var(--text-2); font-size: .88rem; font-weight: 500; }
.names ol { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(15rem, 100%), 1fr)); gap: .6rem 1rem; padding: 0; list-style: none; counter-reset: shooter; }
.names li { position: relative; counter-increment: shooter; }
.names li::before {
  content: counter(shooter); position: absolute; z-index: 1; left: .55rem; top: 50%; translate: 0 -50%;
  display: grid; place-items: center; width: 1.9rem; height: 1.9rem; border-radius: 50%; pointer-events: none;
  background: rgb(0 0 0 / .22); box-shadow: var(--groove); color: var(--muted); font: 600 .8rem/1 var(--body);
  transition: color .25s, box-shadow .35s var(--ease);
}
.names li:has(input:not(:placeholder-shown))::before { background: var(--key-ivory); box-shadow: var(--raise-ivory-sm); color: var(--accent-ink); }
.names input { padding-left: 3.1rem; }

.summary {
  display: grid; gap: 1.1rem; padding: 1.4rem; border-radius: var(--r-lg);
  background: var(--surface); border: 1px solid var(--line-soft); box-shadow: var(--slab);
}
@media (min-width: 62rem) { .summary { position: sticky; top: calc(var(--nav-top) + 4.75rem); } }
.summary-item { display: flex; align-items: center; gap: .9rem; }
.summary-item img { width: 4.5rem; height: 3.4rem; flex: none; border-radius: var(--r-sm); object-fit: cover; }
.summary-item b { display: block; font-family: var(--display); font-weight: 700; font-stretch: 108%; font-size: 1.15rem; line-height: 1.15; }
.summary-item span { display: block; color: var(--muted); font-size: .85rem; }
.summary-lines { display: grid; font-size: .92rem; }
.summary-lines > div { display: flex; justify-content: space-between; gap: 1rem; padding: .6rem 0; border-bottom: 1px solid var(--line-soft); }
.summary-lines dt { color: var(--muted); }
.summary-lines dd { margin: 0; text-align: right; font-variant-numeric: tabular-nums; }
.summary-lines > .sum-total { align-items: baseline; padding-top: 1rem; border-bottom: 0; }
.sum-total dt { color: var(--text); font-weight: 600; }
.sum-total dd { font-family: var(--display); font-weight: 700; font-stretch: 115%; font-size: 1.7rem; line-height: 1; }
.summary .fine { margin-top: -.25rem; }
/* The bot check (core/turnstile.py) shares the Pay button's cell: it is empty until
   Cloudflare wants a click, and a cell of its own would add a gap above the button.
   While Cloudflare shows it (its script marks it .is-shown) it gets a field's room. */
.summary-pay { display: grid; }
.cf-turnstile.is-shown { margin-top: 1rem; }
.summary-pay > .cf-turnstile.is-shown { margin: 0 0 .9rem; }

/* What's left before paying (partials/book_todo.html). Each item sits in a groove: the
   next one raised, a done one an ivory key with its tick. Items that don't apply (the
   company's, until its box is ticked) fold away. Only with JS. */
.todo { display: none; }
.js .todo { display: grid; gap: .45rem; }
.todo-title { color: var(--muted); font-size: .85rem; }
.todo ol { display: grid; padding: 0; list-style: none; }
.todo li { display: grid; grid-template-rows: 1fr; transition: grid-template-rows .45s var(--ease), opacity .35s var(--ease), visibility .45s; }
.todo li.is-off { grid-template-rows: 0fr; opacity: 0; visibility: hidden; }
.todo button {
  position: relative; display: flex; align-items: center; gap: .7rem; width: 100%; min-height: 0;
  overflow: clip; overflow-clip-margin: 8px;
  padding: 0; border: 0; background: none; cursor: pointer;
  color: var(--muted); font: 500 .9rem/1.35 var(--body); text-align: left;
  transition: color .3s var(--ease);
}
.todo button::before {  /* its margin spaces the items: padding on the button would stop a folded one at 9px */
  content: ''; flex: none; width: 1.2rem; height: 1.2rem; margin-block: .28rem; border-radius: 50%;
  background: rgb(0 0 0 / .22); box-shadow: var(--groove); transition: box-shadow .35s var(--ease);
}
.todo button::after { left: .27rem; top: calc(50% - .33rem); width: .66rem; height: .66rem; }
.todo .is-next button { color: var(--text); }
.todo .is-next button::before { background: var(--key); box-shadow: var(--raise-sm); }
.todo .is-done button { color: var(--dim); }
.todo .is-done button::before { background: var(--key-ivory); box-shadow: var(--raise-ivory-sm); }
.todo .is-done button::after { clip-path: inset(0); }
@media (hover: hover) { .todo button:hover { color: var(--text); } }

/* ---------- checkout ---------- */
/* The wallet buttons and the card field are Revolut's iframes (static/js/checkout.js):
   the page frames and sizes them, Revolut draws them. Apple's and Google's buttons keep
   their own look, as their brand rules ask: white on the black, pill-shaped like the caps. */
.pay { position: relative; }
.pay-loading { display: none; }
/* While Revolut sizes its iframes the form is laid out, faint and inert (checkout.js):
   a preview of what's coming. Hidden, it left an empty panel a screen tall on a phone. */
.pay.is-loading .pay-methods { opacity: .2; }
@media (prefers-reduced-motion: no-preference) { .pay-methods { transition: opacity .4s var(--ease); } }
.pay.is-loading .pay-loading {
  display: flex; align-items: center; justify-content: center; gap: .6rem;
  position: absolute; inset: 5.5rem 0 auto; color: var(--muted); font-size: .92rem;
}
.pay-loading::before { content: ''; width: .45rem; height: .45rem; border-radius: 50%; background: currentColor; }
@media (prefers-reduced-motion: no-preference) { .pay-loading::before { animation: pay-pulse 1.2s ease-in-out infinite; } }
@keyframes pay-pulse { 50% { opacity: .25; } }
.pay-wallets { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(11rem, 100%), 1fr)); gap: .75rem; }
.pay-wallets > div { min-width: 0; min-height: 50px; }
.pay-or { display: flex; align-items: center; gap: 1rem; margin: 1.6rem 0 1.1rem; color: var(--muted); font-size: .85rem; }
.pay-or::before, .pay-or::after { content: ''; flex: 1; border-top: 1px solid var(--line); }
.card-field {
  display: grid; align-items: center; min-height: 3rem; padding: .5rem 1rem; background: var(--bg);
  border: 1px solid var(--line); border-radius: var(--r-sm); box-shadow: var(--press);
  transition: border-color .2s;
}
/* Revolut sets color-scheme: normal on its iframe while the field inside is dark, and the
   browser paints that mismatch as an opaque backdrop: a lighter band across the field. */
.card-field iframe { color-scheme: dark !important; }
.card-field.rc-card-field--focused { border-color: rgb(237 234 227 / .7); }
/* Revolut calls an empty field invalid from the start: red only once it's been filled and left */
.card-field.rc-card-field--invalid:not(.rc-card-field--empty, .rc-card-field--focused) { border-color: rgb(217 119 111 / .6); }
.pay-address { min-width: 0; margin: 1.75rem 0 0; padding: 0; border: 0; }
.pay-address legend { padding: 0; font-weight: 600; }
.pay-address label:first-of-type { margin-top: .6rem; }
.pay-address .form-2col label { margin-top: 1rem; }
.pay-card .btn { margin-top: 1.75rem; }
.pay-secure { display: flex; gap: .55rem; margin-top: 1rem; color: var(--muted); font-size: .82rem; line-height: 1.5; }
.pay-secure svg { flex: none; width: 1rem; height: 1rem; margin-top: .12rem; }
.pay-alt { margin-top: .4rem; padding-left: 1.55rem; font-size: .82rem; }
.pay-alt a { color: var(--muted); }
.pay-alt a:hover { color: var(--text); }
.pay-fallback p { margin-bottom: 1.25rem; color: var(--text-2); }

/* ---------- confirmation / cancelled ---------- */
.result { max-width: 36rem; margin-inline: auto; padding: calc(var(--nav-top) + 3.75rem + clamp(2.5rem, 7vw, 5rem)) var(--pad) clamp(3rem, 6vw, 5rem); text-align: center; }
.result-icon { display: grid; place-items: center; width: 4.25rem; height: 4.25rem; margin: 0 auto 1.5rem; border-radius: 50%; background: rgb(141 191 157 / .12); color: var(--ok); }
.result-icon.is-wait { background: rgb(169 188 207 / .12); color: var(--warn); }
.result-icon.is-bad { background: rgb(237 234 227 / .12); color: var(--accent); }
.result-icon svg { width: 1.9rem; height: 1.9rem; }
.result h1 { font-size: clamp(2.1rem, 5vw, 3.4rem); }
.result .lead { margin: 1rem auto 0; }
.result .summary { margin: 2rem 0 1.5rem; text-align: left; }
.result .hero-actions { justify-content: center; }

/* ---------- the customer's profile ----------
   Their bookings, each the booking page's summary panel, and the details form beside
   them from 62rem (under them on a phone). A booking's status is a small chip by its
   number: sage once paid, steel while it waits for the money. What the customer can
   change on a booking folds out under its buttons. */
.profile-who { display: flex; flex-wrap: wrap; align-items: center; gap: .75rem 1.25rem; }
.profile-who .lead { overflow-wrap: anywhere; }
.profile { --h: clamp(1.2rem, 2vw, 1.45rem); display: grid; grid-template-columns: minmax(0, 1fr); gap: 2.5rem 1.25rem; align-items: start; }
/* beside the bookings, the details card starts level with the first of them, under their heading */
@media (min-width: 62rem) {
  .profile { grid-template-columns: minmax(0, 1fr) minmax(18rem, 22rem); }
  .profile-side { position: sticky; top: calc(var(--nav-top) + 4.75rem); margin-top: calc(var(--h) + 1rem); }
}
.profile-h { margin-bottom: 1rem; font-size: var(--h); }
.profile-side .fine { margin-top: 1rem; overflow-wrap: anywhere; }
.profile-side .btn { margin-top: 1.25rem; }
.profile-note { margin-top: 1.5rem; font-size: .92rem; }
.profile-note + .profile-note { margin-top: .35rem; }
.profile-note a { color: var(--text-2); }
.profile-none { display: grid; gap: 1.25rem; justify-items: start; }
.profile-ask { max-width: 34rem; }
.profile-ask .btn { margin-top: 1.25rem; }
.bookings { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(23rem, 100%), 1fr)); gap: 1rem; align-items: start; }
.bookings .summary { position: static; }
.bookings .summary-item > div { min-width: 0; }
.bookings .chip { display: inline-flex; margin-left: .3rem; padding: .05rem .55rem; font-size: .76rem; font-style: normal; vertical-align: .05em; }
.chip.is-ok { color: var(--ok); border-color: rgb(141 191 157 / .3); }
.chip.is-wait { color: var(--warn); border-color: rgb(169 188 207 / .3); }
.booking-actions { display: flex; flex-wrap: wrap; gap: .6rem; }
.booking-edit[open] { flex-basis: 100%; }
.booking-edit summary { list-style: none; }
.booking-edit summary::-webkit-details-marker { display: none; }
.booking-edit[open] summary { background-color: var(--cap-hover); }
.booking-edit .names-title { margin-top: 1rem; }
.booking-edit .btn-primary { margin-top: 1rem; }

/* ---------- legal ---------- */
.legal { max-width: 44rem; }
.legal h2 { font-size: clamp(1.2rem, 2vw, 1.45rem); margin: 2.75rem 0 .2rem; }
.legal h2:first-child { margin-top: 0; }
.legal p, .legal li { color: var(--text-2); line-height: 1.75; margin-top: .8rem; }
.legal ul { padding-left: 1.2rem; }
.legal li { margin-top: .5rem; }
.legal li::marker { color: var(--accent); }
.legal a { color: var(--accent-hi); text-underline-offset: 3px; }
.legal strong { color: var(--text); }

/* ---------- footer ---------- */
.footer {
  margin: clamp(3rem, 7vw, 5rem) var(--frame) var(--frame);
  padding: clamp(2rem, 5vw, 3.75rem) var(--frame-pad) 1.5rem;
  border-radius: var(--r-lg); background: var(--surface); border: 1px solid var(--line-soft);
}
.footer-top { display: grid; gap: 2.25rem; grid-template-columns: repeat(auto-fit, minmax(min(11rem, 100%), 1fr)); }
@media (min-width: 62rem) { .footer-top { grid-template-columns: minmax(0, 1.7fr) repeat(3, minmax(0, 1fr)); } }
.footer-brand img { width: 10rem; height: auto; margin-bottom: 1.1rem; }
.footer-brand p { color: var(--muted); font-size: .92rem; max-width: 24rem; }
.footer-h { margin-bottom: .7rem; font-size: .85rem; color: var(--dim); }
.footer-col a { display: block; width: fit-content; padding: .18rem 0; color: var(--text-2); text-decoration: none; transition: color .2s; }
.footer-col a:hover { color: var(--accent-hi); }
.footer-col address { margin-bottom: .45rem; font-style: normal; color: var(--muted); }
.footer-bottom {
  display: flex; flex-wrap: wrap; justify-content: space-between; align-items: baseline; gap: .4rem 2rem;
  margin-top: 2.75rem; padding-top: 1.4rem; border-top: 1px solid var(--line-soft);
  font-size: .82rem; color: var(--dim);
}
/* The studio's credit. Its logo ships black, so it's drawn through .art's mask in the
   text's colour, and it's centred on the text. The row stays on the baseline, so
   "Served by" still lines up with the copyright and the note. */
.served { display: flex; align-items: center; gap: .4rem; color: var(--dim); text-decoration: none; transition: color .2s; }
.served:hover { color: var(--accent-hi); }
.served .art { width: 3.25rem; aspect-ratio: 62 / 36; background: currentColor; }

.socials { display: flex; gap: .5rem; margin-top: 1.25rem; }
.socials a {
  display: grid; place-items: center; width: 2.5rem; height: 2.5rem; border-radius: 50%;
  color: var(--text-2);
}
.socials a:hover { color: var(--text); }
/* Simple Icons' brand glyphs (CC0): one 24px grid, one weight, all filled. The old
   hand-drawn set mixed a solid WhatsApp with an outlined Viber and looked off-brand. */
.socials svg { width: 1.3rem; height: 1.3rem; fill: currentColor; }

/* On a phone every column stacked, and the footer ran over a screen tall (1,027px at
   360 wide). Here the contact caps sit beside the logo, the phone and email share a
   line, Pages and Legal stand side by side, and the note leads the bottom row with
   the copyright and credit under it on one line. */
@media (max-width: 30rem) {
  .footer-top { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.75rem 1rem; }
  .footer-brand, div.footer-col { grid-column: 1 / -1; }
  .footer-brand { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .9rem 1rem; }
  .footer-brand img { width: 9rem; margin: 0; }
  .footer-brand .socials { order: 1; margin: 0; }
  .footer-brand p:not(.socials) { order: 2; flex-basis: 100%; }
  div.footer-col { display: flex; flex-wrap: wrap; column-gap: 1.25rem; }
  div.footer-col > :is(.footer-h, address) { flex-basis: 100%; }
  .footer-h { margin-bottom: .45rem; }
  .footer-bottom { margin-top: 2rem; padding-top: 1.1rem; }
  .footer-bottom > p:nth-child(2) { order: -1; flex-basis: 100%; }
}

/* ---------- scroll reveal ----------
   Only with JS: <html class="js"> is set inline in the head, so a page whose
   script fails still shows everything. main.js starts a reveal once an element's
   top edge is 8% above the bottom of the screen, however tall it is, staggers
   what arrives together (60ms apart, six at most), and takes the reveal classes
   off once they have played, so hover effects keep their own timing. */
.js .reveal {
  opacity: 0; translate: 0 1rem;
  transition: opacity .7s var(--ease), translate .7s var(--ease);
  transition-delay: calc(min(var(--i, 0), 6) * 60ms);
}
.js .reveal.is-visible { opacity: 1; translate: 0 0; }
/* headings come into focus, a quieter version of the hero titles */
.js :is(h1, h2, h3).reveal { filter: blur(8px); transition: opacity .9s var(--ease), translate .9s var(--ease), filter .9s var(--ease); transition-delay: calc(min(var(--i, 0), 6) * 60ms); }
.js :is(h1, h2, h3).reveal.is-visible { filter: blur(0); }
/* photographs open out of a smaller rounded window and settle into it */
.js .reveal-img { clip-path: inset(6% 6% round var(--r-lg)); transition: clip-path 1.1s var(--ease); transition-delay: calc(min(var(--i, 0), 6) * 60ms); }
.js .reveal-img.is-visible { clip-path: inset(0); }
.js .reveal-img img { transition: transform 1.6s var(--ease) calc(min(var(--i, 0), 6) * 60ms); }
.js .reveal-img:not(.is-visible) img { transform: scale(1.06); }

@media (prefers-reduced-motion: reduce) {
  .js .reveal, .js .reveal-img { opacity: 1; translate: none; clip-path: none; filter: none; transition: none; }
  .js .reveal-img img { transform: none; }
  *, *::before, *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; }
}

/* ---------- inline editing (staff only) ----------
   The markup these hang off is only emitted for request.user.is_staff. */
/* a thin strip down the right edge, its text set sideways (vertical-rl reads top to
   bottom), clear of the film dock and the toasts along the bottom */
.edit-bar {
  position: fixed; right: calc(var(--frame) + .4rem); top: 50%; translate: 0 -50%; z-index: 90;
  writing-mode: vertical-rl; display: flex; align-items: center; gap: .1rem; padding: .3rem;
  max-height: calc(100svh - 2rem); overflow: auto; scrollbar-width: none;
  border-radius: var(--pill); border: 1px solid var(--line);
  background: rgb(22 22 21 / .92); -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px);
  font-size: .8rem; line-height: 1.2; color: var(--muted); white-space: nowrap;
}
/* resets the global label/input form styles, which would otherwise push this off-centre */
.edit-switch {
  display: flex; align-items: center; gap: .55rem; margin: 0; padding: .4rem .4rem .75rem;
  border-radius: var(--pill); font: inherit; color: var(--text); cursor: pointer;
}
.edit-switch:hover { background: rgb(237 234 227 / .08); }
/* the switch stands upright in the strip: the knob slides down to switch on */
.edit-switch input {
  appearance: none; flex: none; position: relative; margin: 0; padding: 0;
  width: 1.1rem; height: 1.9rem; min-height: 0; border-radius: var(--pill); cursor: pointer;
  border: 1px solid rgb(237 234 227 / .28); background: transparent; transition: background .2s, border-color .2s;
}
.edit-switch input::before {
  content: ''; position: absolute; left: 50%; top: 3px; width: .65rem; height: .65rem;
  border-radius: 50%; background: var(--muted); translate: -50% 0; transition: translate .2s, background .2s;
}
.edit-switch input:hover { border-color: rgb(237 234 227 / .5); }
.edit-switch input:checked { background: var(--accent); border-color: var(--accent); }
.edit-switch input:checked::before { translate: -50% .8rem; background: var(--accent-ink); }
.edit-switch input:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.edit-bar a { padding: .75rem .4rem; border-radius: var(--pill); color: var(--text); text-decoration: none; }
.edit-bar a:hover { background: rgb(237 234 227 / .08); }

.edit-on .inline-edit { outline: 1px dashed rgb(237 234 227 / .5); outline-offset: 3px; cursor: text; border-radius: 3px; }
.edit-on .inline-edit:hover { outline-style: solid; background: rgb(237 234 227 / .07); }
.edit-on .inline-edit.is-editing { outline: 2px solid var(--accent); background: rgb(237 234 227 / .1); }
.edit-on .inline-edit-img { cursor: pointer; outline: 2px dashed rgb(237 234 227 / .55); outline-offset: -6px; }
.edit-on .inline-edit-img:hover { outline-style: solid; outline-color: var(--accent); }
/* background layers are pointer-events:none and sit under the copy */
.img-edit-btn {
  position: absolute; top: 5.5rem; right: 1rem; z-index: 5; cursor: pointer;
  padding: .5rem .9rem; border-radius: var(--pill); border: 1px solid rgb(237 234 227 / .5);
  background: rgb(11 11 10 / .8); color: var(--text); font: 600 .8rem var(--body);
}
html:not(.edit-on) .img-edit-btn { display: none; }
.img-edit-btn:hover { background: var(--accent); color: var(--accent-ink); }

/* ---------- included in every session ----------
   Each item is a line drawing in a hairline ring (templates/partials/included.html).
   As the strip comes into view each ring draws round from the top, its drawing draws
   itself in, and the name slides in beside it, one item after another. Every stroke
   has pathLength="1", so one dash pattern draws them all; "1 2" from just past 1
   leaves no round-cap dot at the start of a stroke before it draws. */
.included { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 1rem 2.25rem; }
.included-label { color: var(--muted); font-size: .9rem; }
.included-list { list-style: none; padding: 0; display: flex; flex-wrap: wrap; justify-content: center; gap: .9rem 1.75rem; }
.included-list li { display: flex; align-items: center; gap: .7rem; color: var(--text-2); font-size: .92rem; line-height: 1.3; }
.included-icon {
  flex: none; width: 2.6rem; height: 2.6rem; overflow: visible; color: var(--text);
  fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round;
}
.included-icon .ring { fill: rgb(237 234 227 / .03); stroke: var(--line); stroke-width: .9; }
.included-icon .fill { fill: currentColor; stroke: none; }
@media (max-width: 40rem) { .included-list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .9rem 1rem; } }
@media (prefers-reduced-motion: no-preference) {
  .js .included-icon :not(.fill) {
    stroke-dasharray: 1 2; stroke-dashoffset: 1.01;
    transition: stroke-dashoffset 1.1s var(--ease-io) calc(var(--k) * 120ms + 350ms);
  }
  .js .included-icon .ring {
    rotate: -90deg; transform-box: fill-box; transform-origin: center;
    transition-duration: .9s; transition-delay: calc(var(--k) * 120ms + 100ms);
  }
  .js .included-icon .fill {
    opacity: 0; scale: .2; transform-box: fill-box; transform-origin: center;
    transition: opacity .3s, scale .5s var(--ease); transition-delay: calc(var(--k) * 120ms + 1.2s);
  }
  .js .included-name {
    opacity: 0; translate: -.6rem 0;
    transition: opacity .7s var(--ease), translate .7s var(--ease); transition-delay: calc(var(--k) * 120ms + 400ms);
  }
  .js .included.is-visible .included-icon :not(.fill) { stroke-dashoffset: 0; }
  .js .included.is-visible .included-icon .fill { opacity: 1; scale: 1; }
  .js .included.is-visible .included-name { opacity: 1; translate: none; }
}

/* ---------- small pieces ---------- */
.back-link {
  display: inline-flex; align-items: center; gap: .4rem; color: var(--muted); text-decoration: none;
  font-size: .92rem; font-weight: 500; transition: color .2s;
}
.back-link::before {
  content: ''; width: 1rem; height: 1rem; background: currentColor; rotate: 180deg;
  -webkit-mask: var(--i-arrow) center / contain no-repeat; mask: var(--i-arrow) center / contain no-repeat;
  transition: translate .3s var(--ease);
}
.back-link:hover { color: var(--text); }
@media (hover: hover) { .back-link:hover::before { translate: -3px 0; } }

.split-frame { overflow: hidden; border-radius: var(--r-lg); }
.split-frame .split-img { transition: transform 1.4s var(--ease); }
@media (hover: hover) { .split-frame:hover .split-img { transform: scale(1.03); } }

/* team building enquiry */
.enquire { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.5rem 3rem; align-items: start; }
@media (min-width: 62rem) { .enquire { grid-template-columns: minmax(0, 1fr) minmax(0, 1.6fr); } .enquire-intro { position: sticky; top: 7rem; } }
.enquire-intro { display: grid; gap: 1rem; }
.enquire-intro h2 { max-width: 12ch; }
.contact-lines { display: grid; gap: .25rem; margin-top: .5rem; }
.contact-lines a { width: fit-content; font-family: var(--display); font-weight: 700; font-stretch: 105%; font-size: clamp(1.1rem, 2vw, 1.35rem); text-decoration: none; transition: color .2s; }
.contact-lines a:hover { color: var(--accent-hi); }
.contact-form .btn { margin-top: 1.5rem; }
/* .step-card zeroes each first label: keep the grid's rows, and the label after it, clear of the field above */
.contact-form .form-2col { row-gap: 1rem; margin-bottom: 1rem; }

/* company invoice block — partials/business_invoice.html */
.biz { margin-top: 1.25rem; padding-top: 1.1rem; border-top: 1px solid var(--line-soft); }
.biz-toggle { display: flex; gap: .75rem; align-items: flex-start; margin: 0; cursor: pointer; color: var(--text); font-weight: 500; }
.biz-toggle input { flex: none; margin-top: .15rem; }
.biz-toggle small { display: block; margin-top: .2rem; color: var(--muted); font-weight: 400; font-size: .84rem; }
/* it unfolds while the box is ticked: CSS only, so a form sent back with errors opens it without JS */
.biz-fields {
  display: grid; grid-template-rows: 0fr; visibility: hidden; min-width: 0; margin: 0; padding: 0; border: 0;
  transition: grid-template-rows .55s var(--ease), visibility 0s .55s;
}
.biz-fields > .form-2col { min-height: 0; overflow: hidden; margin: 0 -6px; padding: 1rem 6px 6px; }
.biz:has(.biz-toggle input:checked) .biz-fields { grid-template-rows: 1fr; visibility: visible; transition-delay: 0s; }
@media (prefers-reduced-motion: reduce) { .biz-fields { transition: none; } }

/* ---- reticle cursor (public site, mouse only) ----
   A native `cursor: url()` so it never lags the pointer. It tightens over anything
   clickable; text fields keep the I-beam. The click mark is .shot, added by main.js.
   Each reticle carries a black underlay so it reads on the ivory buttons too. */
@media (pointer: fine) {
  body:not(.dash) {
    cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32'%3E%3Cg fill='none' stroke-linecap='round'%3E%3Cg stroke='%230B0B0A' stroke-width='3'%3E%3Ccircle cx='16' cy='16' r='9'/%3E%3Cpath d='M16 2v6M16 24v6M2 16h6M24 16h6'/%3E%3C/g%3E%3Cg stroke='%23EDEAE3' stroke-width='1.25'%3E%3Ccircle cx='16' cy='16' r='9'/%3E%3Cpath d='M16 2v6M16 24v6M2 16h6M24 16h6'/%3E%3C/g%3E%3C/g%3E%3Ccircle cx='16' cy='16' r='1.5' fill='%23EDEAE3' stroke='%230B0B0A' stroke-width='.75'/%3E%3C/svg%3E") 16 16, crosshair;
  }
  body:not(.dash) :is(a, button, label, select, summary, [role="button"], [role="option"]) {
    cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32'%3E%3Cg fill='none' stroke-linecap='round'%3E%3Cg stroke='%230B0B0A' stroke-width='3'%3E%3Ccircle cx='16' cy='16' r='6'/%3E%3Cpath d='M16 5v6M16 21v6M5 16h6M21 16h6'/%3E%3C/g%3E%3Cg stroke='%23EDEAE3' stroke-width='1.5'%3E%3Ccircle cx='16' cy='16' r='6'/%3E%3Cpath d='M16 5v6M16 21v6M5 16h6M21 16h6'/%3E%3C/g%3E%3C/g%3E%3Ccircle cx='16' cy='16' r='2' fill='%23EDEAE3' stroke='%230B0B0A' stroke-width='.75'/%3E%3C/svg%3E") 16 16, pointer;
  }
}
.shot { position: fixed; z-index: 2147483647; width: 0; height: 0; pointer-events: none; }
.shot::before, .shot::after { content: ""; position: absolute; left: 0; top: 0; translate: -50% -50%; }
.shot::before {  /* hit marker: four diagonal ticks */
  width: 40px; height: 40px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40'%3E%3Cg stroke-linecap='round'%3E%3Cpath stroke='%230B0B0A' stroke-width='3.5' d='M9 9l6 6M31 9l-6 6M9 31l6-6M31 31l-6-6'/%3E%3Cpath stroke='%23EDEAE3' stroke-width='1.75' d='M9 9l6 6M31 9l-6 6M9 31l6-6M31 31l-6-6'/%3E%3C/g%3E%3C/svg%3E");
  animation: shot-mark .32s cubic-bezier(.2, .8, .3, 1) forwards;
}
.shot::after {  /* shock ring */
  width: 10px; height: 10px; border: 1px solid var(--text); border-radius: 50%;
  animation: shot-ring .5s cubic-bezier(.1, .7, .3, 1) forwards;
}
@keyframes shot-mark { from { scale: .55; opacity: 1; } 55% { scale: 1.05; opacity: 1; } to { scale: 1.15; opacity: 0; } }
@keyframes shot-ring { from { width: 10px; height: 10px; opacity: .9; } to { width: 72px; height: 72px; opacity: 0; } }
