/* University of Life — editorial.
   Every colour derives from the teachers' own photographs: their shared studio backdrop
   samples at hue 28°, so paper, umber and ink sit on that hue and the portraits and the
   page become one material. Gold is the single accent; each teacher's colour arrives as
   data (--t). Playfair carries the masthead, Cormorant the human sentence, Manrope is
   quiet. */
:root{
  --paper:#f2efed; --paper-2:#e9e3dd; --umber:#141d2e; --umber-2:#1c2740; --ink:#131a29;
  /* 31/08: the dark rooms were umber (#231e19). The name stays -- it is used in a
     hundred places and a rename would be a bigger change than the colour. */
  --gold:#b8893a; --gold-lit:#d9b26a; --gold-pale:#efe2c6;
  --on-paper:#1d1610; --on-paper-2:rgba(29,22,16,.66); --on-paper-3:rgba(29,22,16,.42);
  --on-umber:#f2efed; --on-umber-2:rgba(242,239,237,.66); --on-umber-3:rgba(242,239,237,.38);
  --hair-paper:rgba(29,22,16,.12); --hair-umber:rgba(242,239,237,.14);
  --display:'Playfair Display',Georgia,serif;
  --voice:'Cormorant Garamond',Georgia,serif;
  --sans:'Manrope',-apple-system,'Segoe UI',Arial,sans-serif;
  --ease:cubic-bezier(.22,.61,.36,1);
  --ease-out:cubic-bezier(.16,1,.3,1);
  --wrap:1280px;
}
html[lang="he"],html[lang="ar"]{--sans:'Assistant',Arial,sans-serif}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{margin:0;background:var(--paper);color:var(--on-paper);font-family:var(--sans);
  font-size:17px;line-height:1.6;-webkit-font-smoothing:antialiased;overflow-x:hidden}
img{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
p{margin:0}
h1,h2,h3{margin:0;font-weight:400;text-wrap:balance}

/* rooms: each section is either paper or umber, and its type follows */
.room{position:relative;padding-block:clamp(80px,11vw,150px)}
.room.paper{background:var(--paper);color:var(--on-paper)}
.room.umber{background:var(--umber);color:var(--on-umber)}
.room.paper .muted{color:var(--on-paper-2)} .room.umber .muted{color:var(--on-umber-2)}
.room.paper .faint{color:var(--on-paper-3)} .room.umber .faint{color:var(--on-umber-3)}
.room.paper .hair{border-color:var(--hair-paper)} .room.umber .hair{border-color:var(--hair-umber)}
.wrap{max-width:var(--wrap);margin-inline:auto;padding-inline:clamp(20px,5vw,56px)}

/* ---- type system ---- */
.mast{font-family:var(--display);font-weight:400;letter-spacing:-.035em;line-height:.94;
  font-size:clamp(2.8rem,6.4vw,6.1rem)}
.mast i{font-style:italic;font-weight:400}
.h2{font-family:var(--display);font-weight:400;letter-spacing:-.025em;line-height:1;
  font-size:clamp(2.3rem,5.2vw,4.4rem)}
.h3{font-family:var(--display);font-weight:400;letter-spacing:-.015em;line-height:1.12;
  font-size:clamp(1.35rem,2.2vw,1.85rem)}
.voice{font-family:var(--voice);font-style:italic;font-weight:500;line-height:1.28;
  font-size:clamp(1.35rem,2.4vw,2rem)}
.eyebrow{display:flex;align-items:center;gap:12px;font-size:.66rem;letter-spacing:.28em;
  text-transform:uppercase;font-weight:800;color:var(--gold);margin-bottom:26px}
.eyebrow::before{content:"";width:38px;height:1px;background:currentColor;opacity:.7}
.lede{font-size:1.08rem;max-width:58ch;line-height:1.7}
.small{font-size:.84rem;letter-spacing:.02em}
/* words rise in sequence as a headline enters — see runtime.js, which wraps each word */
.js .w{display:inline-block;opacity:0;transform:translateY(.55em) rotate(1.2deg);
  transform-origin:0 100%;
  transition:opacity .9s var(--ease-out),transform .9s var(--ease-out);
  transition-delay:calc(var(--i,0)*55ms);
  /* safety: the observer is the fast path; this is the guarantee. If .in never arrives, the
     words still surface at 1.6s. A headline that can stay invisible is a page that lies. */
  animation:wordsafe .01s linear 1.6s forwards}
.js .in .w{opacity:1;transform:none;animation:none}
@keyframes wordsafe{to{opacity:1;transform:none}}

/* ---- header ---- */
header.site{position:fixed;inset-inline:0;top:0;z-index:60;
  transition:background .4s var(--ease),border-color .4s var(--ease),color .4s}
header.site .bar{display:flex;align-items:center;gap:28px;height:84px}
header.site.on-umber{color:var(--on-umber)}
header.site.scrolled{background:color-mix(in srgb,var(--paper) 88%,transparent);
  backdrop-filter:saturate(140%) blur(16px);border-bottom:1px solid var(--hair-paper)}
header.site.scrolled.on-umber{background:color-mix(in srgb,var(--umber) 86%,transparent);
  border-bottom-color:var(--hair-umber)}
.brand{display:flex;align-items:center;gap:12px;flex-shrink:0;font-family:var(--display);
  font-size:1.05rem;letter-spacing:-.01em;white-space:nowrap}
.brand img{width:46px;height:46px;object-fit:contain}   /* 38 -> 46, client 8/31 */
nav.main{display:flex;gap:26px;margin-inline-start:auto;font-size:.82rem;font-weight:700;
  letter-spacing:.02em}
nav.main a{position:relative;padding:6px 0;opacity:.72;transition:opacity .25s}
nav.main a:hover,nav.main a[aria-current]{opacity:1}
nav.main a::after{content:"";position:absolute;inset-inline-start:0;bottom:0;height:1px;
  width:0;background:var(--gold);transition:width .32s var(--ease)}
nav.main a:hover::after,nav.main a[aria-current]::after{width:100%}
.hd{display:flex;align-items:center;gap:14px;margin-inline-start:20px}
.langs{display:flex;gap:2px;font-size:.66rem;font-weight:800;letter-spacing:.1em;direction:ltr}
.langs a{padding:6px 9px;opacity:.5;border-radius:999px;transition:opacity .2s,background .2s}
.langs a[aria-current]{opacity:1;background:color-mix(in srgb,var(--gold) 18%,transparent)}
.btn{display:inline-flex;align-items:center;gap:10px;padding:15px 28px;border-radius:999px;
  font-weight:800;font-size:.84rem;letter-spacing:.04em;text-transform:uppercase;
  border:1px solid transparent;cursor:pointer;font-family:var(--sans);position:relative;
  overflow:hidden;transition:transform .25s var(--ease),box-shadow .25s,background .25s,color .25s}
.btn:hover{transform:translateY(-2px)}
.btn-ink{background:var(--ink);color:var(--paper)}
.btn-ink:hover{box-shadow:0 18px 40px -18px rgba(19,26,41,.6)}
.btn-paper{background:var(--paper);color:var(--ink)}
.btn-line{border-color:currentColor;opacity:.85}
.btn-line:hover{opacity:1;background:color-mix(in srgb,currentColor 8%,transparent)}
.btn-gold{background:var(--gold);color:var(--paper)}
.btn-gold::after{content:"";position:absolute;inset:0;
  background:linear-gradient(105deg,transparent 35%,rgba(255,255,255,.45),transparent 65%);
  transform:translateX(-130%);transition:transform .8s var(--ease)}
.btn-gold:hover::after{transform:translateX(130%)}
.burger{display:none;background:none;border:1px solid currentColor;color:inherit;
  width:42px;height:42px;border-radius:999px;cursor:pointer;font-size:1rem;opacity:.8}
@media(max-width:1280px){
  nav.main{display:none;position:absolute;inset-inline:16px;top:84px;background:var(--paper);
    color:var(--on-paper);border:1px solid var(--hair-paper);border-radius:18px;
    flex-direction:column;gap:0;padding:10px;box-shadow:0 30px 70px -20px rgba(19,26,41,.35)}
  nav.main.open{display:flex}
  nav.main a{padding:14px 16px;border-bottom:1px solid var(--hair-paper);opacity:1}
  nav.main a:last-child{border-bottom:0}
  .burger{display:block;margin-inline-start:auto}
}
/* THE DOOR IS ALWAYS ON THE SCREEN (founder, 05/09: "when the site is not full size I can't
   enter the dashboards, I don't see it").
   Between 981px and 1280px — a laptop window that is simply not maximised — there was NO way
   in: this rule hid the Join button because the nav had folded into the menu, and the menu's
   own sign-in link was `display:none!important` above 980. Two rules, each sensible alone,
   left a 300-pixel band of screens with nothing to press. Now: with the nav folded away there
   is ROOM for the button, so it stays; only under 520px does the menu carry the door instead,
   and there the menu always holds it. */
@media(max-width:520px){ .hd .btn{display:none} }
/* A header must survive its own TRANSLATIONS (founder, 04/09: "in Russian I can't see the
   join button"). At 1440 the Russian bar needs ~1500px — brand + seven long words + the
   languages + "Присоединиться" (198px against "Join" at 91px) — so the button was pushed off
   the right edge of the screen and a Russian reader never saw the one thing the page is for.
   A width breakpoint cannot know that; fitting is the test, not pixels. runtime.js measures
   the bar and sets .tight, in any language, at any window size. */
header.site.tight nav.main{display:none;position:absolute;inset-inline:16px;top:84px;
  background:var(--paper);color:var(--on-paper);border:1px solid var(--hair-paper);
  border-radius:18px;flex-direction:column;gap:0;padding:10px;
  box-shadow:0 30px 70px -20px rgba(19,26,41,.35)}
header.site.tight nav.main.open{display:flex}

/* An open menu must never be taller than the room it has (founder, 04/09: "there's no way to
   scroll down in the hamburger menu"). It is absolutely positioned inside a FIXED header, so
   the page behind it cannot bring the last items into view — on a 600px-tall phone the menu
   ended at 625px and Эфир, О проекте and the sign-in link were simply unreachable. It scrolls
   itself now, and runtime.js sets the exact height it may have when it opens. */
nav.main.open{max-height:calc(100vh - 140px);overflow-y:auto;overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch}
@supports (height: 100dvh){ nav.main.open{max-height:calc(100dvh - 140px)} }
header.site.tight nav.main a{padding:14px 16px;border-bottom:1px solid var(--hair-paper);opacity:1}
header.site.tight nav.main a:last-child{border-bottom:0}
header.site.tight .burger{display:block;margin-inline-start:auto}
header.site.tight .hd{margin-inline-start:14px}
/* the two further steps down, taken only when the measurement says so */
header.site.tighter .brand > span{display:none}
header.site.tightest .hd .btn{display:none}
header.site.tighter .nav-signin,header.site.tightest .nav-signin{display:block}

/* scroll progress: one gold hairline across the top */
.progress{position:fixed;top:0;inset-inline-start:0;height:2px;width:0;background:var(--gold);
  z-index:70;transition:width .1s linear}

/* ---- hero ---- */
.hero,.detail,.shop-head{padding-top:calc(84px + clamp(40px,7vw,96px))}
.hero .wrap{display:grid;grid-template-columns:1.15fr .85fr;gap:clamp(32px,5vw,80px);align-items:end}
@media(max-width:980px){.hero .wrap{grid-template-columns:1fr;gap:48px}}
.hero .mast{margin:10px 0 32px}
.hero .voice{max-width:34ch;margin-bottom:28px;color:var(--on-paper-2)}
.hero .cta{display:flex;gap:14px;flex-wrap:wrap;margin-top:36px}
.hero .stats{display:flex;gap:40px;flex-wrap:wrap;margin-top:48px;padding-top:28px;
  border-top:1px solid var(--hair-paper)}
.hero .stats b{display:block;font-family:var(--display);font-size:2.4rem;line-height:1;
  font-weight:400;letter-spacing:-.02em}
.hero .stats span{font-size:.72rem;letter-spacing:.1em;text-transform:uppercase;font-weight:800;
  color:var(--on-paper-3);display:block;margin-top:8px}

/* the week, now ink on paper — a drawn instrument, not a glowing one */
.week{position:relative;aspect-ratio:1;width:min(100%,540px);margin-inline:auto;margin-inline-end:0}
@media(max-width:980px){.week{margin-inline:auto}}
.week svg{width:100%;height:100%;overflow:visible}
.week .ring{fill:none;stroke:var(--hair-paper);stroke-width:1}
.week .arc{fill:none;stroke:var(--ink);stroke-width:1.2;opacity:.55}
.week .hand{stroke:var(--gold);stroke-width:1.4}
.week .daylabel{font-family:var(--sans);font-size:9px;font-weight:800;letter-spacing:.2em;fill:var(--on-paper-3)}
.week .shabbat{fill:var(--on-paper-3);font-size:9px;font-weight:800;letter-spacing:.22em;font-family:var(--sans)}
.week .mid{text-anchor:middle}
.week .mid .k{fill:var(--on-paper-3);font-size:7.5px;font-weight:800;letter-spacing:.24em;text-transform:uppercase;font-family:var(--sans)}
.week .mid .v{fill:var(--ink);font-family:var(--display);font-size:24px;letter-spacing:-.02em}
.week .mid .n{fill:var(--on-paper-2);font-size:11px;font-weight:700;font-family:var(--sans)}
.week .mid .t{fill:var(--on-paper-3);font-size:8.5px;font-family:var(--sans)}
.week .dot{transform-origin:center;transform-box:fill-box;transition:r .4s var(--ease)}
.week .dot.next{filter:drop-shadow(0 0 6px currentColor)}
.js .week .arc{stroke-dasharray:1400;stroke-dashoffset:1400;animation:draw 2.4s var(--ease) .4s forwards}
@keyframes draw{to{stroke-dashoffset:0}}
.js .week .dot{opacity:0;animation:pop .6s var(--ease-out) forwards}
@keyframes pop{from{opacity:0;transform:scale(.3)}to{opacity:1;transform:none}}
.js .hero .rise{opacity:0;transform:translateY(22px);animation:rise .9s var(--ease-out) forwards}
@keyframes rise{to{opacity:1;transform:none}}

/* ---- the gallery: teachers as circles ---------------------------------------
   Was a horizontal rail of full-bleed rectangles that bled off both edges. Now a
   grid of circular portraits, which suits ten faces far better: a circle crops to
   the face and nothing else, every teacher gets the same weight, and the row
   reads as a group rather than a queue you have to drag.

   Done entirely in CSS. The markup is unchanged in all three languages — the same
   <a class="panel"><span class="num"><img><span class="cap"> — because the change
   is how it LOOKS, and rewriting three files to move a class name is how the
   Hebrew one quietly ends up different from the other two.

   Each teacher carries their own accent as --t (inline, already there). Nothing
   here invents a colour; it just finally uses the one that was always on the tag. */
.gallery{padding:0;overflow:hidden;position:relative}
/* padding-BLOCK, not the shorthand. `padding: X 0 Y` also set the inline sides to 0,
   overriding .wrap's own padding-inline — invisible on desktop, where .wrap is narrower
   than the viewport anyway and the margin comes from `margin-inline:auto`. On a phone the
   wrap IS the viewport, so the heading and the lede sat hard against the screen edge. */
.gallery .head{padding-block:clamp(64px,9vw,120px) clamp(40px,5vw,64px);position:relative;z-index:2}

/* the ground: three slow drifts in teacher colours, well under the type. This is
   the only decorative motion on the page that nobody asked to start, so it is
   slow enough to read as light rather than as animation. */
.gallery::before,.gallery::after{content:"";position:absolute;z-index:0;pointer-events:none;
  border-radius:50%;filter:blur(90px);opacity:.16}
.gallery::before{width:46vw;height:46vw;inset-block-start:-8vw;inset-inline-start:-10vw;
  background:radial-gradient(circle,#75d4c5,transparent 65%);
  animation:drift-a 34s var(--ease) infinite alternate}
.gallery::after{width:52vw;height:52vw;inset-block-end:-14vw;inset-inline-end:-12vw;
  background:radial-gradient(circle,#a3a9ff,transparent 65%);
  animation:drift-b 41s var(--ease) infinite alternate}
@keyframes drift-a{to{transform:translate3d(6vw,4vw,0) scale(1.15)}}
@keyframes drift-b{to{transform:translate3d(-5vw,-3vw,0) scale(1.1)}}

.rail{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));
  gap:clamp(28px,3.4vw,52px) clamp(18px,2.4vw,36px);
  padding:0 clamp(20px,5vw,56px) clamp(64px,8vw,104px);
  position:relative;z-index:2;overflow:visible}
@media(max-width:1100px){.rail{grid-template-columns:repeat(3,minmax(0,1fr))}}
@media(max-width:620px){.rail{grid-template-columns:repeat(2,minmax(0,1fr));gap:34px 18px}}

.panel{position:relative;display:flex;flex-direction:column;align-items:center;
  text-align:center;color:var(--on-umber);isolation:isolate;
  transition:transform .55s var(--ease-out)}
/* the portrait: a circle, with the teacher's own colour as the ring that closes
   around it on hover. The ring is a conic sweep on a mask, so it draws rather
   than simply appearing. */
.panel img{position:relative;z-index:1;width:100%;aspect-ratio:1;height:auto;
  border-radius:50%;object-fit:cover;object-position:50% 18%;
  background:var(--umber-2);
  filter:saturate(.86) contrast(1.05) brightness(.92);
  transition:filter .6s var(--ease-out),transform .9s var(--ease-out),
             box-shadow .55s var(--ease-out);
  box-shadow:0 0 0 1px var(--hair-umber),0 18px 40px -30px rgb(0 0 0 / .9)}
/* The ring is sized to the PORTRAIT, not to the panel. `inset:-7px` looked right
   and drew an ellipse: the panel is a flex column whose height includes the name
   and both captions, so a 50% radius on that box is an oval hanging past the
   text. The image is width x width, so the ring is too — width plus its offset,
   with aspect-ratio doing the rest. */
.panel::before{content:"";position:absolute;z-index:0;
  top:-7px;inset-inline-start:-7px;width:calc(100% + 14px);aspect-ratio:1;height:auto;
  border-radius:50%;
  background:conic-gradient(from -90deg,var(--t,var(--gold-lit)) 0turn,
             var(--t,var(--gold-lit)) var(--sweep,0turn),transparent var(--sweep,0turn));
  -webkit-mask:radial-gradient(farthest-side,transparent calc(100% - 2px),#000 calc(100% - 2px));
          mask:radial-gradient(farthest-side,transparent calc(100% - 2px),#000 calc(100% - 2px));
  opacity:0;transition:opacity .4s var(--ease-out),--sweep .85s var(--ease-out)}
@property --sweep{syntax:"<angle>";inherits:true;initial-value:0turn}
.panel:hover::before,.panel:focus-visible::before{opacity:1;--sweep:1turn}

.panel .num{position:absolute;top:-2px;inset-inline-start:2px;z-index:3;font-family:var(--display);
  font-style:italic;font-size:.92rem;color:var(--on-umber-3);
  transition:color .4s var(--ease),transform .5s var(--ease-out)}

.panel .cap{display:block;margin-top:18px;position:relative;z-index:2}
.panel .cap b{display:block;font-family:var(--display);font-weight:400;
  font-size:clamp(1.25rem,1.7vw,1.6rem);letter-spacing:-.02em;line-height:1.1;
  transition:transform .45s var(--ease-out)}
/* two lines' worth of room whether the discipline needs it or not, so one long
   name ("Spiritual logic and the Language of Transition") does not push its own
   keyword down and break the baseline the whole row is read along. */
.panel .cap span{display:block;margin-top:7px;font-size:.74rem;letter-spacing:.03em;
  color:var(--t,var(--gold-lit));font-weight:700;opacity:.9;
  min-height:2.6em;line-height:1.3}
.panel .cap small{display:block;margin-top:8px;font-size:.63rem;color:var(--on-umber-3);
  letter-spacing:.13em;text-transform:uppercase;font-weight:800;
  transition:color .4s var(--ease),letter-spacing .5s var(--ease-out)}

/* hover: the face comes forward and the rest of the room steps back — the same
   sentence the week wheel speaks when you reach for a dot. */
.panel:hover,.panel:focus-visible{transform:translateY(-8px)}
.panel:hover img,.panel:focus-visible img{filter:saturate(1.06) contrast(1.02) brightness(1.04);
  transform:scale(1.03);
  box-shadow:0 0 0 1px transparent,0 26px 50px -26px color-mix(in srgb,var(--t,#000) 55%,transparent)}
.panel:hover .cap b,.panel:focus-visible .cap b{transform:translateY(-2px)}
.panel:hover .cap small,.panel:focus-visible .cap small{color:var(--on-umber-2);letter-spacing:.17em}
.panel:hover .num,.panel:focus-visible .num{color:var(--t,var(--gold-lit));transform:translateY(-3px)}
.rail:hover .panel{opacity:.5;transition:opacity .4s var(--ease)}
.rail:hover .panel:hover,.rail:focus-within .panel:focus-visible{opacity:1}

/* they arrive one after another as the section comes into view */
.js .gallery .panel{opacity:0;transform:translateY(26px)}
.js .gallery.in .panel{animation:rise .85s var(--ease-out) forwards}
/* the stagger is nth-child rather than an inline --n: the index already exists in
   the document order, and writing it a second time into ten tags in three
   languages is three places for it to disagree. */
.js .gallery.in .panel:nth-child(1){animation-delay:.00s}
.js .gallery.in .panel:nth-child(2){animation-delay:.07s}
.js .gallery.in .panel:nth-child(3){animation-delay:.14s}
.js .gallery.in .panel:nth-child(4){animation-delay:.21s}
.js .gallery.in .panel:nth-child(5){animation-delay:.28s}
.js .gallery.in .panel:nth-child(6){animation-delay:.35s}
.js .gallery.in .panel:nth-child(7){animation-delay:.42s}
.js .gallery.in .panel:nth-child(8){animation-delay:.49s}
.js .gallery.in .panel:nth-child(9){animation-delay:.56s}
.js .gallery.in .panel:nth-child(10){animation-delay:.63s}

/* 🔴 the resting state, stated here and not left to the animation — see the hero.
   With reduced motion the reveal never runs, so without this the entire teacher
   grid stays at opacity 0 and the section is empty. */
@media(prefers-reduced-motion:reduce){
  .js .gallery .panel{opacity:1!important;transform:none!important}
  .gallery::before,.gallery::after{animation:none}
  .panel:hover,.panel:focus-visible{transform:none}
  .panel:hover img,.panel:focus-visible img{transform:none}
}

/* the rail arrows drove a scroller that no longer exists. Hidden, not deleted:
   the markup is shared with two other languages and the JS that binds them is
   already guarded, so there is nothing to break — but a button that scrolls
   nothing must not be reachable by a keyboard either. */
.rail-nav{display:none}

/* ---- values + path on paper ---- */
.cols3{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(24px,4vw,56px)}
@media(max-width:860px){.cols3{grid-template-columns:1fr}}
.val{padding-top:28px;border-top:1px solid var(--hair-paper)}
.val .g{font-family:var(--display);font-style:italic;font-size:1.4rem;color:var(--gold);display:block;margin-bottom:18px}
.val .h3{margin-bottom:12px}
.val p{color:var(--on-paper-2);font-size:.96rem}
ol.path{list-style:none;counter-reset:s;margin:0;padding:0;display:grid;grid-template-columns:repeat(4,1fr);gap:clamp(20px,3vw,40px)}
@media(max-width:980px){ol.path{grid-template-columns:repeat(2,1fr)}}
@media(max-width:560px){ol.path{grid-template-columns:1fr}}
ol.path li{counter-increment:s;padding-top:24px;border-top:1px solid var(--hair-paper);position:relative}
ol.path li::before{content:counter(s,decimal-leading-zero);font-family:var(--display);font-style:italic;
  font-size:2.6rem;line-height:1;color:var(--gold);display:block;margin-bottom:16px;letter-spacing:-.02em}
ol.path b{display:block;font-family:var(--display);font-weight:400;font-size:1.35rem;letter-spacing:-.015em;margin-bottom:8px}
ol.path span{display:block;font-size:.94rem;color:var(--on-paper-2)}

/* ---- editorial list: courses & products, on umber ---- */
.list{border-top:1px solid var(--hair-umber)}
.row{display:grid;grid-template-columns:64px 1.3fr 2fr auto;gap:clamp(18px,3vw,40px);align-items:center;
  padding:26px 0;border-bottom:1px solid var(--hair-umber);position:relative}
/* hover slides the CONTENT with a transform; padding would re-flow the grid tracks and the
   description column visibly jumped */
.row > *{transition:transform .35s var(--ease)}
.row:hover > *{transform:translateX(12px)}
html[dir=rtl] .row:hover > *{transform:translateX(-12px)}
.row::before{content:"";position:absolute;inset-inline-start:0;top:0;bottom:0;width:0;background:var(--gold);
  transition:width .35s var(--ease)}
.row:hover::before{width:3px}
.row .idx{font-family:var(--display);font-style:italic;color:var(--on-umber-3);font-size:1.05rem}
.row .ttl{font-family:var(--display);font-weight:400;font-size:clamp(1.15rem,1.8vw,1.55rem);letter-spacing:-.015em;line-height:1.15}
.row .ttl small{display:block;font-family:var(--sans);font-size:.68rem;letter-spacing:.16em;text-transform:uppercase;
  font-weight:800;color:var(--gold-lit);margin-top:8px}
.row .dsc{font-size:.93rem;color:var(--on-umber-2)}
.row .end{text-align:end;white-space:nowrap}
.row .price{font-family:var(--display);font-size:1.65rem;letter-spacing:-.02em;display:block}
.row .by{display:flex;align-items:center;gap:9px;justify-content:flex-end;margin-top:8px;font-size:.78rem;color:var(--on-umber-2)}
.row .by img{width:26px;height:26px;border-radius:999px;object-fit:cover;border:1px solid var(--t,var(--gold))}
@media(max-width:860px){.row{grid-template-columns:44px 1fr;gap:14px}.row .dsc{grid-column:2}.row .end{grid-column:2;text-align:start}
  .row .by{justify-content:flex-start}}

/* ---- schedule on paper ---- */
.days{display:grid;grid-template-columns:repeat(5,1fr);gap:clamp(16px,2.4vw,32px)}
@media(max-width:980px){.days{grid-template-columns:repeat(2,1fr)}}
@media(max-width:560px){.days{grid-template-columns:1fr}}
.day{padding-top:22px;border-top:1px solid var(--hair-paper)}
.day > b{display:block;font-family:var(--display);font-weight:400;font-size:1.4rem;letter-spacing:-.02em;margin-bottom:16px}
.slot{display:flex;gap:12px;align-items:center;padding:10px 0}
.slot + .slot{border-top:1px solid var(--hair-paper)}
.slot img{width:38px;height:38px;border-radius:999px;object-fit:cover;flex:0 0 38px;border:1.5px solid var(--t,var(--gold))}
.slot .tm{font-family:var(--display);font-size:1.1rem;min-width:48px;font-variant-numeric:tabular-nums}
.slot .nm{font-size:.9rem;color:var(--on-paper-2)}
/* a session that carries its own name says it under the teacher's (04/09) */
.slot .ttl{display:block;font-size:.78rem;color:var(--on-paper-3,var(--on-paper-2));opacity:.85}

/* ---- close ---- */
.close .wrap{max-width:820px;text-align:center}
.close .h2{margin-bottom:22px}
.close .lede{margin-inline:auto;margin-bottom:34px}

footer.site{background:var(--ink);color:var(--on-umber-2);padding:70px 0 34px;font-size:.9rem}
footer.site .cols{display:grid;grid-template-columns:2fr 1fr 1fr;gap:40px}
@media(max-width:760px){footer.site .cols{grid-template-columns:1fr}}
footer.site h4{font-size:.64rem;letter-spacing:.24em;text-transform:uppercase;color:var(--gold-lit);margin:0 0 16px;font-weight:800}
footer.site ul{list-style:none;margin:0;padding:0;display:grid;gap:10px}
footer.site a:hover{color:var(--on-umber)}
footer.site .fb{font-family:var(--display);font-size:1.6rem;color:var(--on-umber);margin-bottom:12px;letter-spacing:-.02em}
footer.site .btm{margin-top:48px;padding-top:22px;border-top:1px solid var(--hair-umber);display:flex;
  justify-content:space-between;gap:20px;flex-wrap:wrap;font-size:.78rem;color:var(--on-umber-3)}

/* reveal: enhancement only — see the .js probe in <head> */
.js .reveal{opacity:0;transform:translateY(26px);transition:opacity .9s var(--ease-out),transform .9s var(--ease-out);
  transition-delay:var(--d,0ms)}
.js .reveal.in{opacity:1;transform:none}
.tilt{transform-style:preserve-3d;transition:transform .5s var(--ease-out)}
:focus-visible{outline:2px solid var(--gold);outline-offset:3px;border-radius:4px}
@media(prefers-reduced-motion:reduce){
  *{animation:none!important;transition-duration:.01ms!important}
  .js .reveal,.js .w,.js .hero .rise,.js .week .dot{opacity:1;transform:none}
}

/* =====================================================================
   TEACHER PAGE HERO — was an inline 1fr 1fr grid that never collapsed,
   so at 390px the portrait was crushed into a 175px box, face cut off.
   ===================================================================== */
.thero{display:grid;grid-template-columns:1fr 1fr;gap:clamp(28px,5vw,72px);align-items:end;
  padding-top:calc(84px + clamp(32px,6vw,80px))}
.thero-txt{padding-bottom:clamp(56px,8vw,110px)}
.thero-img{position:relative;aspect-ratio:3/4;overflow:hidden;border-radius:8px 8px 0 0}
.thero-img img{position:absolute;inset:-8% 0;width:100%;height:116%;object-fit:cover;object-position:50% 20%}
@media(max-width:860px){
  .thero{grid-template-columns:1fr;gap:0;padding-top:84px;align-items:start}
  /* portrait FIRST and full-bleed: on a phone the face is the page */
  .thero-img{order:-1;aspect-ratio:4/5;border-radius:0;margin-inline:calc(-1*clamp(16px,4vw,24px))}
  .thero-txt{padding:28px 0 44px}
  .thero-txt .mast{font-size:clamp(2.6rem,13vw,3.6rem)}
}

/* =====================================================================
   PHONE — a different rhythm, not a smaller desktop.
   Measured 2026-08-22 at 390px: 12 screens tall, every room kept its
   80px desktop padding, langs pushed 52px off the right edge.
   ===================================================================== */
@media(max-width:600px){
  /* header geometry: brand text (211px) + burger + langs (107px) > 390. The logo carries
     the brand; text goes. Burger moves to the END where a thumb expects it. */
  header.site .bar{height:64px;gap:10px}
  .brand > span{display:none}
  .brand img{width:40px;height:40px}
  .hd{margin-inline-start:auto;gap:6px;order:2}
  .burger{margin-inline-start:0;order:3;width:40px;height:40px}
  .langs a{padding:6px 7px;font-size:.62rem}
  nav.main{top:64px}
  .progress{height:2px}

  /* rooms: halve the vertical rhythm */
  .room{padding-block:clamp(44px,9vw,60px)}
  .hero{padding-top:calc(64px + 28px)}
  .hero .mast{font-size:clamp(2.7rem,13.5vw,3.6rem);margin-bottom:20px}
  .hero .voice{font-size:1.2rem;max-width:none;margin-bottom:18px}
  .hero .lede{font-size:.98rem}
  .hero .stats{gap:20px 28px;margin-top:30px;padding-top:20px}
  .hero .stats b{font-size:1.9rem}
  /* CTAs: one primary pill, one quiet text link — not two full-width uppercase slabs */
  .hero .cta{flex-direction:column;align-items:flex-start;gap:12px;margin-top:26px}
  .hero .cta .btn{padding:14px 22px;font-size:.78rem;width:auto}
  .hero .cta .btn-line{border:0;padding:6px 0;text-transform:none;letter-spacing:0;font-size:.92rem;
    font-weight:700;opacity:.8;text-decoration:underline;text-underline-offset:4px}
  .week{width:min(100%,330px);margin-top:8px}

  /* gallery: show ~1.35 panels so the next face invites the swipe; arrows are for pointers */
  /* the same shorthand, a second time, in the mobile block — and this is the copy that was
     actually biting, since the desktop one is masked by `margin-inline:auto`. One fix that
     moves one of two homes is half a fix. */
  .gallery .head{padding-block:44px 18px}
  .panel{flex-basis:72vw;aspect-ratio:3/4}
  .rail{gap:8px;padding-bottom:44px;scroll-snap-type:x mandatory;scroll-padding-inline:16px}
  .rail-nav{margin-top:-6px;margin-bottom:14px;justify-content:space-between;align-items:center}
  .rail-nav button{display:none}
  .swipe-hint{font-size:.7rem;letter-spacing:.18em;text-transform:uppercase;font-weight:800;opacity:.55}

  /* values + path: compact, not one full card each */
  .cols3{gap:0}
  .val{padding:18px 0;border-top:1px solid var(--hair-paper)}
  .val .g{font-size:1.05rem;margin-bottom:8px;display:inline-block;margin-inline-end:10px;vertical-align:middle}
  .val .h3{display:inline;font-size:1.2rem}
  .val p{margin-top:6px;font-size:.92rem}
  ol.path{gap:0}
  ol.path li{padding:16px 0;display:grid;grid-template-columns:44px 1fr;gap:12px;align-items:baseline}
  ol.path li::before{font-size:1.5rem;margin:0}
  ol.path li > div{min-width:0}
  ol.path b{font-size:1.15rem;margin-bottom:4px}
  ol.path span{font-size:.9rem}
  .val{padding:22px 0}
  .val p{margin-top:8px}
  .h2{font-size:clamp(2rem,9vw,2.6rem)}

  /* editorial rows: price leads, description shortens, author is a chip */
  .row{grid-template-columns:1fr auto;gap:6px 14px;padding:16px 0;align-items:start}
  .row .idx{display:none}
  .row .ttl{grid-column:1;font-size:1.08rem}
  .row .ttl small{margin-top:4px;font-size:.62rem}
  .row .dsc{grid-column:1;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;font-size:.86rem}
  .row .end{grid-column:2;grid-row:1/3;text-align:end}
  .row .price{font-size:1.35rem}
  .row .by{margin-top:6px;font-size:.72rem}
  .row .by img{width:20px;height:20px}
  .row:hover > *{transform:none}

  /* schedule: five days as one compact list, not five stacked cards */
  .days{grid-template-columns:1fr;gap:0}
  .day{padding:12px 0;border-top:1px solid var(--hair-paper);display:grid;grid-template-columns:96px 1fr;gap:0 12px;align-items:start}
  .day > b{font-size:1.05rem;margin:0;padding-top:8px}
  .slot{padding:7px 0}
  .slot + .slot{border-top:0}
  .slot img{width:30px;height:30px;flex-basis:30px}
  .slot .tm{font-size:.95rem;min-width:42px}
  .slot .nm{font-size:.88rem}

  .close .h2{font-size:2rem}
  footer.site{padding:44px 0 28px}
}
/* arrows only where there is a pointer to click them */
@media(hover:none) and (pointer:coarse){ .rail-nav button{display:none} }
@media(min-width:601px){ .swipe-hint{display:none} }

/* ── HERO FILM, FULL SCREEN ───────────────────────────────────────────────────
   The 30s class film fills the hero and everything that was already there sits
   on top of it, unchanged: eyebrow, mast, voice, lede, CTAs, stats, the week.
   The hero is now an `umber` room — the site's own name for a dark one — so
   site.js flips the header to light over it and .muted/.faint/.hair resolve to
   their on-umber variants by the same rule every other dark room follows. Only
   the background is overridden, because the film IS the background.

   The source is 854x480 and a full viewport is wider than that, so it is being
   asked to do something it was not shot for. The scrim below is what makes that
   honest rather than merely soft: a warm umber wash plus a vignette, which is
   also what keeps type legible over moving faces. */
.hero-full{background:var(--umber);min-height:100svh;display:flex;align-items:center;
  padding-block:calc(84px + clamp(28px,5vw,56px)) clamp(48px,7vw,90px);overflow:hidden}
.hero-full .wrap{position:relative;z-index:2;width:100%}
.hero-bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0;
  /* the faces sit high in frame; keep them out of the crop's bottom edge */
  object-position:50% 42%}
.hero-scrim{position:absolute;inset:0;z-index:1;pointer-events:none;
  background:
    linear-gradient(to bottom, rgb(24 20 16 / .55) 0%, rgb(24 20 16 / .42) 45%, rgb(24 20 16 / .82) 100%),
    radial-gradient(120% 85% at 50% 45%, transparent 25%, rgb(24 20 16 / .55) 100%)}
/* RTL and LTR alike: the reading column gets the denser side of the wash. */
.hero-full .wrap::before{content:"";position:absolute;inset-block:0;inset-inline-start:-8vw;
  width:min(72ch,68%);z-index:-1;pointer-events:none;
  background:linear-gradient(to var(--scrim-dir,right), rgb(24 20 16 / .5), transparent)}
html[dir="rtl"] .hero-full .wrap::before{--scrim-dir:left}

/* type on film */
.hero-full .voice{color:var(--on-umber-2)}
.hero-full .mast,.hero-full .stats b{color:var(--on-umber);
  text-shadow:0 1px 40px rgb(24 20 16 / .5)}
.hero-full .lede{color:var(--on-umber-2)}
.hero-full .eyebrow{color:var(--gold-lit)}
.hero-full .stats{border-top-color:var(--hair-umber)}
.hero-full .stats span{color:var(--on-umber-3)}
.hero-full .btn-line{border-color:rgb(242 239 237 / .5);color:var(--on-umber)}
.hero-full .btn-line:hover{border-color:var(--on-umber);background:rgb(242 239 237 / .08)}
.hero-full .btn-ink{background:var(--paper);color:var(--ink)}
.hero-full .btn-ink:hover{background:#fff}

/* the week, drawn in light — it was ink on paper and the paper is gone */
.hero-full .week .ring{stroke:var(--hair-umber)}
.hero-full .week .arc{stroke:var(--on-umber);opacity:.5}
.hero-full .week .daylabel,.hero-full .week .shabbat{fill:var(--on-umber-3)}
.hero-full .week .mid .k{fill:var(--on-umber-3)}
.hero-full .week .mid .v{fill:var(--on-umber)}
.hero-full .week .mid .n{fill:var(--on-umber-2)}
.hero-full .week .mid .t{fill:var(--on-umber-3)}

@media(max-width:980px){
  .hero-full{min-height:100svh;padding-block:calc(64px + 24px) 40px}
  .hero-full .wrap::before{inset-inline-start:-20vw;width:140%}
}
/* Reduced motion: the poster carries the same frame and nothing moves. The film
   is paused and its source dropped in site.js — `display:none` here would have
   hidden a file the browser still downloaded and decoded, which looks exactly
   like it worked. */

/* ── the fixed header needs its own ground ───────────────────────────────────
   `on-umber` colours the header light, and site.js applies it correctly — but a
   light header over a brightly-lit face is still unreadable. Colour was never
   the problem; the absence of a ground behind it was. */
.hero-full::before{content:"";position:absolute;inset-inline:0;top:0;height:180px;z-index:1;
  pointer-events:none;
  background:linear-gradient(to bottom,rgb(24 20 16 / .72),rgb(24 20 16 / .28) 60%,transparent)}

/* ── HERO: the words arrive ──────────────────────────────────────────────────
   The site already had two animation vocabularies — `.rise` (a block lifts) and
   `.w` (a headline's words surface one by one, wrapped by site.js). Both are
   reused rather than replaced: a third dialect on the same page reads as three
   authors. What is added is the ORDER — eyebrow, mast, voice, lede, buttons,
   stats, each a beat behind the last — and a little more travel, because over a
   moving film a 22px lift is invisible. */
.js .hero-full .rise{opacity:0;transform:translateY(30px);
  animation:rise 1.05s var(--ease-out) forwards}
.js .hero-full .mast .w{transition-duration:1.05s;transition-delay:calc(var(--i,0)*70ms)}
/* the eyebrow's rule draws itself in */
.js .hero-full .eyebrow::before{width:0;animation:rule .9s var(--ease-out) .35s forwards}
@keyframes rule{to{width:38px}}
/* the buttons settle last, and lift to meet the cursor */
.hero-full .btn{transition:transform .35s var(--ease-out),background .3s,border-color .3s,box-shadow .35s}
.hero-full .btn:hover{transform:translateY(-2px);box-shadow:0 14px 30px -18px rgb(0 0 0 / .8)}
/* the stats count in behind a wipe, one after another */
.js .hero-full .stats > div{opacity:0;animation:rise .8s var(--ease-out) forwards}
.js .hero-full .stats > div:nth-child(1){animation-delay:.86s}
.js .hero-full .stats > div:nth-child(2){animation-delay:.96s}
.js .hero-full .stats > div:nth-child(3){animation-delay:1.06s}

/* ── THE WEEK: a drawn instrument that answers the cursor ────────────────────
   The ring and the arc already drew themselves in. What was missing is that the
   dots are the only part carrying information — a teacher, a day, a time, live
   in a <title> — and nothing invited anyone to go near them. */
.hero-full .week{transition:transform .8s var(--ease)}
.week .dot{cursor:pointer;
  transition:transform .35s var(--ease-out),filter .35s var(--ease-out),opacity .3s}
.week .dot:hover{transform:scale(2.1);filter:drop-shadow(0 0 10px currentColor)}
/* the hovered dot is the subject: the rest step back so it reads alone */
.week:hover .dot{opacity:.45}
.week:hover .dot:hover{opacity:1}
.week .hand{transition:opacity .4s var(--ease)}
.week:hover .hand{opacity:.35}
/* the next session keeps its pulse, but never while the wheel is being read */
.js .week .dot.next{animation:beat 2.6s var(--ease) infinite}
@keyframes beat{0%,100%{filter:drop-shadow(0 0 4px currentColor)}
                50%{filter:drop-shadow(0 0 13px currentColor)}}
.week:hover .dot.next{animation:none}
/* the ring answers too, so the whole instrument feels live rather than the dots alone */
.hero-full .week .ring{transition:stroke .5s var(--ease)}
.hero-full .week:hover .ring{stroke:rgb(242 239 237 / .3)}

@media(prefers-reduced-motion:reduce){
  .week .dot:hover{transform:none}
  .js .week .dot.next{animation:none}
}

/* 🔴 2026-08-24 — A HEADLINE THAT CAN STAY INVISIBLE IS A PAGE THAT LIES.
   site.css already carries that sentence, about its own safety net; I then broke
   the net. The reduced-motion block above resets `.js .hero .rise` to opacity 1,
   and my `.js .hero-full .rise{opacity:0}` has the SAME specificity and comes
   LATER — so it won, `*{animation:none!important}` stopped the animation that
   would have revealed it, and a reader with reduced motion got a full-screen
   film with no headline, no buttons and no stats on top of it. Caught on the
   mobile screenshot, where there was nothing on the page at all.

   Anything I animate into view must state its resting state HERE, last, in the
   same breath as the animation. An entrance is a way of arriving, never the
   condition of existing. */
@media(prefers-reduced-motion:reduce){
  .js .hero-full .rise,
  .js .hero-full .stats > div,
  .js .hero-full .mast .w{opacity:1!important;transform:none!important}
  .js .hero-full .eyebrow::before{width:38px!important}
}

/* ── THE PRINCIPLES, OVER THE WHITE VOID ─────────────────────────────────────
   The film is a warm off-white void with distant figures passing something from
   hand to hand — knowledge handed on, which is what this section says in words.
   It sits BEHIND the whole section rather than in a frame, so the figures drift
   through the page itself.

   This is a `paper` room, so unlike the hero the type here is INK ON LIGHT. The
   veil is therefore a paper-toned wash, not a dark one: enough to hold the copy
   at full contrast, little enough that the figures still read. A dark scrim would
   have been the hero's answer to a different question. */
.principles{position:relative;overflow:hidden;isolation:isolate}
.principles > .wrap{position:relative;z-index:2}
.principles-bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0;
  object-position:50% 45%}
/* 8/24 second pass: the first veil was tuned for "don't disturb the text" and buried the film —
   the figures were a rumour. Opened up so the hand-off actually reads. The type keeps its cover
   from the reading-column wash below, which is where it is actually needed; the open half of the
   frame no longer pays for the text's legibility. */
.principles-veil{position:absolute;inset:0;z-index:1;pointer-events:none;
  background:
    linear-gradient(to bottom, var(--paper) 0%, color-mix(in srgb,var(--paper) 58%,transparent) 18%,
                    color-mix(in srgb,var(--paper) 48%,transparent) 72%, var(--paper) 100%),
    radial-gradient(120% 85% at 50% 50%, transparent 42%,
                    color-mix(in srgb,var(--paper) 52%,transparent) 100%)}
/* the reading column gets a little more cover than the open space beside it */
.principles > .wrap::before{content:"";position:absolute;inset-block:-4vh;inset-inline-start:-6vw;
  width:min(74ch,72%);z-index:-1;pointer-events:none;
  background:linear-gradient(to var(--veil-dir,right),
             color-mix(in srgb,var(--paper) 80%,transparent) 35%, transparent)}
html[dir="rtl"] .principles > .wrap::before{--veil-dir:left}
@media(max-width:980px){
  .principles > .wrap::before{inset-inline-start:-20vw;width:150%}
}
/* Reduced motion: the poster carries the same image and nothing moves; site.js
   pauses it and drops the source, so the file is not downloaded either. */

/* 8/31 — the broadcast and closing rooms get films too, on the same mechanics as
   .principles and, deliberately, the SAME veil: a heavier wash made the film a rumour
   again and left paper-coloured bands at the top and bottom, so the section read as a
   strip of video rather than a room with a film in it. One veil, three rooms. */
.broadcast,.close.has-film{position:relative;overflow:hidden;isolation:isolate}
.broadcast > .wrap,.close.has-film > .wrap{position:relative;z-index:2}
.broadcast-bg,.close-bg{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:0}
.broadcast-bg{object-position:50% 22%}
.close-bg{object-position:50% 45%}
.broadcast-veil,.close-veil{position:absolute;inset:0;z-index:1;pointer-events:none;
  background:
    linear-gradient(to bottom, var(--paper) 0%, color-mix(in srgb,var(--paper) 58%,transparent) 10%,
                    color-mix(in srgb,var(--paper) 48%,transparent) 88%, var(--paper) 100%),
    radial-gradient(120% 85% at 50% 50%, transparent 42%,
                    color-mix(in srgb,var(--paper) 52%,transparent) 100%)}
/* the day grid and the centred closing column each get their own local cover, so the
   type is legible without the whole frame paying for it */
.broadcast .days{position:relative}
.broadcast .days::before{content:"";position:absolute;inset:-16vh -14vw;z-index:-1;pointer-events:none;
  background:radial-gradient(55% 52% at 50% 50%, color-mix(in srgb,var(--paper) 76%,transparent) 25%,
             transparent 78%)}
.close.has-film > .wrap::before{content:"";position:absolute;inset:-16vh -16vw;z-index:-1;pointer-events:none;
  background:radial-gradient(50% 50% at 50% 50%, color-mix(in srgb,var(--paper) 74%,transparent) 25%,
             transparent 78%)}

/* 8/31 reconciliation — the live stylesheet had drifted ahead of this generator by 99
   selectors of hand-editing, and had lost these four along the way. Folded back in, so a
   rebuild is no longer a regression. Everything above this line came from the live file. */
.rail::-webkit-scrollbar{display:none}
.panel::after{content:"";position:absolute;inset:0;z-index:1;
  background:linear-gradient(to top,rgba(20,29,46,.92) 0%,rgba(20,29,46,.45) 34%,transparent 62%)}
.rail-nav button:hover{background:color-mix(in srgb,var(--on-umber) 10%,transparent);border-color:var(--on-umber-2)}
html[dir=rtl] .rail-nav button{transform:scaleX(-1)}

/* ============================================================== the shop
 * 8/31. The store was a text list; the client asked for something that behaves like a
 * shop. Cards carry the artwork that was already in the database and never shown, and the
 * category bar filters cards that are all present in the HTML — so the page stays one
 * static file a crawler reads whole, and a filter costs no request.
 */
.shop-head{padding-bottom:clamp(28px,4vw,44px)}
.shop-note{margin-top:22px;font-size:.9rem;font-weight:700;letter-spacing:.02em;
  color:var(--gold);display:inline-flex;align-items:center;gap:10px}
.shop-note::before{content:"";width:26px;height:1px;background:var(--gold)}

.cats{display:flex;gap:8px;overflow-x:auto;scrollbar-width:none;padding-bottom:22px;
  margin-bottom:22px;border-bottom:1px solid var(--hair-paper)}
.cats::-webkit-scrollbar{display:none}
.cat{flex:0 0 auto;background:none;border:1px solid var(--hair-paper);color:var(--on-paper-2);
  font:inherit;font-size:.86rem;font-weight:700;padding:9px 17px;border-radius:100px;
  cursor:pointer;transition:background .18s,color .18s,border-color .18s}
.cat:hover{border-color:var(--on-paper-3);color:var(--on-paper)}
.cat.is-on{background:var(--ink);border-color:var(--ink);color:var(--paper)}

.shop-bar{display:flex;flex-wrap:wrap;gap:14px 22px;align-items:center;margin-bottom:30px}
.sel{display:inline-flex;align-items:center;gap:9px;font-size:.82rem;color:var(--on-paper-3);
  font-weight:700;letter-spacing:.06em;text-transform:uppercase}
.sel select{font:inherit;font-size:.86rem;font-weight:700;text-transform:none;letter-spacing:0;
  color:var(--on-paper);background:transparent;border:1px solid var(--hair-paper);
  border-radius:8px;padding:7px 11px;cursor:pointer}
.sel select:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
.shop .count{margin-inline-start:auto;font-size:.82rem;color:var(--on-paper-3);
  font-variant-numeric:tabular-nums}

.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(238px,1fr));
  gap:clamp(14px,2vw,26px)}
.shelf{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:16px}
/* on a shelf the footer line stays one line: label and "about the course" side by side */
.shelf .pcard-foot .price{font-size:.9rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.shelf .pcard-cta{white-space:nowrap}

.pcard{display:flex;flex-direction:column;background:var(--paper);color:var(--on-paper);
  border:1px solid var(--hair-paper);border-radius:10px;overflow:hidden;text-decoration:none;
  transition:transform .22s var(--ease),box-shadow .22s,border-color .22s}
.room.umber .pcard{background:var(--umber-2);color:var(--on-umber);border-color:var(--hair-umber)}
.pcard:hover{transform:translateY(-3px);border-color:var(--t,var(--gold));
  box-shadow:0 14px 34px rgba(19,26,41,.13)}
.pcard-art{position:relative;display:block;aspect-ratio:1;background:var(--paper-2);overflow:hidden}
.room.umber .pcard-art{background:var(--umber)}
.pcard-art img{width:100%;height:100%;object-fit:cover;display:block;
  transition:transform .5s var(--ease)}
.pcard:hover .pcard-art img{transform:scale(1.035)}
.pcard-kind{position:absolute;inset-block-start:10px;inset-inline-start:10px;
  background:rgba(20,29,46,.78);color:#f2efed;font-size:.66rem;font-weight:800;
  letter-spacing:.09em;text-transform:uppercase;padding:5px 10px;border-radius:100px;
  backdrop-filter:blur(4px)}
.pcard-body{display:flex;flex-direction:column;gap:9px;padding:15px 16px 16px;flex:1}
.pcard-body b{font-family:var(--display);font-weight:400;font-size:1.12rem;line-height:1.2;
  letter-spacing:-.01em}
.pcard-by{display:flex;align-items:center;gap:8px;font-size:.8rem;color:var(--on-paper-3)}
.room.umber .pcard-by{color:var(--on-umber-3)}
.pcard-by img{border-radius:50%;object-fit:cover}
.pcard-foot{display:flex;align-items:center;justify-content:space-between;gap:12px;
  margin-top:auto;padding-top:11px;border-top:1px solid var(--hair-paper)}
.room.umber .pcard-foot{border-top-color:var(--hair-umber)}
.pcard-foot .price{font-weight:800;font-size:1.02rem;font-variant-numeric:tabular-nums}
.pcard-cta{font-size:.76rem;font-weight:800;letter-spacing:.09em;text-transform:uppercase;
  color:var(--t,var(--gold));opacity:.75;transition:opacity .18s}
.pcard:hover .pcard-cta{opacity:1}
.empty{padding:60px 0;text-align:center;color:var(--on-paper-3)}

/* ====================================================== course & product
 * One layout for both: the words on one side, the thing itself on the other.
 */
/* header clearance for these two comes from the .hero rule above -- one home for the 84px */
.dwrap{display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(30px,5vw,64px);align-items:start}
.dtxt{min-width:0}
.back{display:inline-flex;align-items:center;gap:8px;font-size:.8rem;font-weight:800;
  letter-spacing:.09em;text-transform:uppercase;color:var(--on-paper-3);
  text-decoration:none;margin-bottom:26px}
.back::before{content:"←"}
html[dir=rtl] .back::before{content:"→"}
.back:hover{color:var(--on-paper)}
.dprice{font-family:var(--display);font-size:clamp(2rem,3.6vw,2.8rem);margin:24px 0 0;
  font-variant-numeric:tabular-nums}
.dprice span{font-family:var(--sans);font-size:.8rem;font-weight:800;letter-spacing:.1em;
  color:var(--on-paper-3);vertical-align:.7em;margin-inline-start:4px}
.facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(148px,1fr));gap:18px 26px;
  margin:30px 0 0;padding:22px 0 0;border-top:1px solid var(--hair-paper)}
.facts div{min-width:0}
.facts dt{font-size:.7rem;font-weight:800;letter-spacing:.12em;text-transform:uppercase;
  color:var(--on-paper-3);margin-bottom:6px}
.facts dd{margin:0;font-size:.98rem;font-weight:700}
.facts dd a{display:inline-flex;align-items:center;gap:9px;color:inherit;text-decoration:none}
.facts dd a img{border-radius:50%;object-fit:cover}
.facts dd a:hover{color:var(--t,var(--gold))}
.dimg{border-radius:12px;overflow:hidden;background:var(--paper-2);
  border:1px solid var(--hair-paper);position:sticky;top:96px}
.dimg img{width:100%;height:auto;display:block}
@media(max-width:860px){
  .dwrap{grid-template-columns:1fr}
  .dimg{position:static;order:-1}
  .grid{grid-template-columns:repeat(auto-fill,minmax(150px,1fr))}
  .pcard-body b{font-size:1rem}
}

/* A hidden element must be hidden. .btn, .rule and .pcard all set display, which outranks
   the user-agent [hidden] rule — the shop's filters and the account page's provider button
   both depend on this. Found 8/31 when a disabled Google button stayed on screen. */
[hidden]{display:none!important}

/* The school's name belongs in the hero. It was in the header, the footer and the browser
   tab, and nowhere a first-time visitor actually reads. 8/31, at the client's request. */
.hero-brand{display:block;font-family:var(--display);font-weight:400;font-style:italic;
  font-size:clamp(1.05rem,1.7vw,1.42rem);letter-spacing:.01em;color:var(--gold-lit);
  margin-bottom:14px}
.hero-full .hero-brand{color:var(--gold-lit)}
/* On a phone, ONE small line above the headline, not two. The name is the line the client
   asked for, so the eyebrow gives way rather than the hero growing: a guard in
   awaken-tests holds the phone home page under ten screens and this addition tipped it. */
@media(max-width:640px){ .hero .hero-brand + .eyebrow{display:none} }

/* the enlarged logo left the widest nav item wrapping to two lines at ~1440px */
nav.main a{white-space:nowrap}
@media(min-width:981px){ header.site .bar{gap:22px} nav.main{gap:22px} }

/* The languages a teacher works in (client 31/08). */
.langs-say{display:flex;flex-wrap:wrap;align-items:baseline;gap:8px 12px;margin-top:18px;
  font-size:.9rem}
.langs-say span{font-size:.7rem;font-weight:800;letter-spacing:.12em;text-transform:uppercase;
  color:var(--on-umber-3)}
.langs-say b{font-weight:700;padding:4px 11px;border-radius:100px;
  border:1px solid var(--hair-umber);color:var(--on-umber-2)}
.room.paper .cats .cat[data-lang]{white-space:nowrap}

/* What it costs, said once, on the home page (client 31/08: "the homepage must be
   attractive and impressive"). Three numbers, no persuasion — the price of the cheapest
   material is read from the catalogue at build time, so it cannot drift from the shop. */
.offers{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));
  gap:clamp(18px,3vw,38px)}
.offer-i{display:flex;flex-direction:column;gap:6px;padding-top:22px;
  border-top:1px solid var(--hair-paper)}
.offer-i b{font-family:var(--display);font-weight:400;font-size:clamp(2.2rem,4vw,3.1rem);
  line-height:1;letter-spacing:-.02em;color:var(--gold);font-variant-numeric:tabular-nums}
.offer-i .ot{font-weight:800;font-size:1rem;margin-top:8px}
.offer-i .od{font-size:.92rem;color:var(--on-paper-2);line-height:1.5}
/* the umber rooms on the home page now hold cards, which carry their own ground */
.room.umber .grid{margin-top:4px}

/* A phone reads the home page as a sequence, not a catalogue: it shows two of each and the
   "all courses" / "all of the shop" button right beside them. The guard in awaken-tests
   holds this page under ten screens, and covers are tall — this is how both survive. */
@media(max-width:640px){
  .home-grid > :nth-child(n+3){display:none}
}
@media(max-width:640px){
  /* the three numbers sit side by side on a phone -- they are short, and stacking them
     cost a third of a screen the home page does not have to spare */
  .offers{grid-template-columns:1fr 1fr;gap:20px 16px}
  .offer-i b{font-size:2rem}
  .offer-i .ot{font-size:.92rem}
  .offer-i .od{font-size:.85rem}
  .room.offer{padding-block:clamp(56px,9vw,80px)}
}
@media(max-width:620px){
  /* On a phone the home page SAMPLES the faculty — six of the ten, with the full list one
     tap away in the nav and the count stated in the hero. All ten stay in the HTML for a
     crawler; five rows of portraits was a third of the page's whole length. */
  .gallery .rail > .panel:nth-child(n+7){display:none}
}

/* "Join" is for a new person; someone who already has an account needs a way in that does
   not ask them what brings them here (founder, 31/08 — an admin had no door). */
.signin{font-size:.82rem;font-weight:700;opacity:.72;white-space:nowrap;text-decoration:none;
  color:inherit;transition:opacity .2s}
.signin:hover{opacity:1;text-decoration:underline;text-underline-offset:4px}
@media(max-width:520px){ .signin{display:none} }
/* The quiet sign-in lives beside the Join button on a wide screen and inside the menu on a
   phone, where the header has no room for it. One of the two is always reachable. */
/* The sign-in link inside the menu: shown whenever the MENU is the navigation — the width
   breakpoint, or the measured collapse — and hidden only when the full nav is on the bar. */
.nav-signin{display:none}
@media(max-width:1280px){ .nav-signin{display:block} }
header.site.tight .nav-signin{display:block}

/* ============================================================== the footer
 * 31/08. It was three thin columns with a hole where the brand should stand, and no way to
 * change language after a long scroll -- the switcher lived only in a header the reader had
 * left far behind. Now it carries the mark, the whole site, both doors, and the languages.
 */
footer.site .cols{grid-template-columns:1.5fr 1fr 1fr .7fr}
.fbrand{max-width:34ch}
.fmark{display:inline-flex;align-items:center;gap:13px;text-decoration:none;color:inherit;
  margin-bottom:16px}
.fmark img{width:44px;height:44px;object-fit:contain;flex:0 0 auto}
.fmark .fb{font-family:var(--display);font-size:1.32rem;letter-spacing:-.01em;margin:0}
.fbrand p{margin:0 0 10px;line-height:1.55}
.fbrand .fnote{font-size:.85rem;color:var(--on-umber-3)}
.flang h4{margin-bottom:14px}
.flangs{display:flex;gap:8px;margin-bottom:18px}
.flangs a{display:inline-flex;align-items:center;justify-content:center;min-width:38px;
  padding:7px 10px;border:1px solid var(--hair-umber);border-radius:100px;font-size:.74rem;
  font-weight:800;letter-spacing:.08em;text-decoration:none;color:var(--on-umber-2);
  transition:border-color .2s,color .2s,background .2s}
.flangs a:hover{border-color:var(--on-umber-3);color:var(--on-umber)}
.flangs a[aria-current]{background:var(--on-umber);border-color:var(--on-umber);color:var(--umber)}
.ftop{display:inline-flex;align-items:center;gap:8px;font-size:.82rem;font-weight:700;
  text-decoration:none;color:var(--on-umber-3);transition:color .2s}
.ftop::before{content:"↑"}
.ftop:hover{color:var(--on-umber)}
.fmotto{font-family:var(--voice);font-style:italic;font-size:1rem}
@media(max-width:900px){
  footer.site .cols{grid-template-columns:1fr 1fr}
  .fbrand{grid-column:1/-1;max-width:none}
}
@media(max-width:560px){
  footer.site .cols{grid-template-columns:1fr;gap:30px}
  .fmotto{display:block;margin-top:10px}
}

/* ============================================================ on a phone
 * 31/08, founder: "it needs to look like an app."
 *
 * Not a rewrite into a native shell — the pages are still pages, and a crawler still reads
 * them. What makes a site feel like an app on a phone is smaller and more boring than that:
 * nothing under a thumb's width, one thing per screen, and controls that stay reachable
 * instead of scrolling away. That is what this block does.
 */
@media(max-width:640px){
  /* A thumb is about 44px. Everything you can press gets at least that. */
  .cat{padding:12px 18px;font-size:.9rem}
  .sel select{padding:12px 14px;font-size:.95rem}
  .btn{padding:16px 24px;font-size:1rem}
  nav.main a{padding:16px 18px}
  .flangs a{min-width:52px;padding:12px 14px;font-size:.8rem}
  .ftop{padding:10px 0}
  /* Measured, not guessed: the footer's list links came back 35px, the header's language
     switcher 28px, and .btn-line 36px because it is an <a> whose line-height, not padding,
     set its height. */
  footer.site .cols li a{display:block;padding:11px 0}
  /* padding alone left these at 36px: the line box is 16px and 10+10 does not reach 44.
     A flex box with a min-height is the only way to state the size and mean it. */
  .langs a{display:inline-flex;align-items:center;justify-content:center;
    min-height:44px;min-width:44px;padding:0 10px}
  .hd .langs{gap:2px}
  a.btn,a.btn-line{min-height:52px;display:inline-flex;align-items:center;justify-content:center}

  /* The category bar behaves like an app's segmented control: it stays put at the top of
     the shop while the grid scrolls under it, so choosing a category never means scrolling
     back up to change your mind. */
  .shop .cats{position:sticky;top:64px;z-index:20;margin-inline:calc(-1 * var(--pad,20px));
    padding-inline:var(--pad,20px);padding-block:12px;
    background:color-mix(in srgb,var(--paper) 94%,transparent);
    backdrop-filter:blur(10px);border-bottom:1px solid var(--hair-paper)}

  /* Cards get bigger and rounder — one column of things you can actually see, rather than
     two thumbnails of things you cannot. */
  .grid{grid-template-columns:1fr 1fr;gap:12px}
  .pcard{border-radius:16px}
  .pcard-body{padding:13px 14px 15px}
  .pcard-foot{padding-top:10px}
  /* The kind badge wrapped to two lines and spilled past the card's rounded corner at
     165px. One line, and it gives up characters before it gives up the shape. */
  .pcard-kind{max-width:calc(100% - 20px);white-space:nowrap;overflow:hidden;
    text-overflow:ellipsis;font-size:.6rem;padding:4px 9px}

  /* Two labelled rows of filters cost most of a screen before a single product. On a phone
     the label is the placeholder, and the two controls share one line. */
  .shop-bar{gap:10px}
  .sel{flex:1 1 0;min-width:0}
  .sel > span{display:none}
  .sel select{width:100%}
  .shop .count{flex:1 0 100%;margin-inline-start:0;text-align:end}

  /* Type that was set for a wide column, reset for a narrow one. */
  .lede{font-size:1rem}
  .room{padding-block:clamp(56px,10vw,90px)}
  /* the eyebrow was landing on the header's bottom edge */
  .hero,.detail,.shop-head{padding-top:calc(84px + clamp(28px,7vw,60px))}
}

/* The header shrinks as you scroll on a phone, the way an app's title bar does. The class
   is `scrolled`, which site.js already sets past 24px — I first wrote `.small` from memory
   and checked: no such class exists. */
@media(max-width:640px){
  header.site.scrolled .bar{height:62px}
  header.site.scrolled .brand img{width:32px;height:32px}
  header.site .bar{transition:height .22s var(--ease)}
  header.site .brand img{transition:width .22s var(--ease),height .22s var(--ease)}
  /* the sticky category bar has to sit under whichever height the header currently is */
  .shop .cats{top:62px}
}
@media(max-width:640px){
  /* Two things in the hero were sized for a wide screen and cost a third of a phone screen
     between them: the week ring (337px of decorative clock, when the broadcast section below
     states the same week properly) and a stats row that wrapped onto three lines. */
  /* The ring is the decorative half of a fact the broadcast section states plainly a
     screen below. On a phone it gives way rather than the page growing. */
  .hero .week{max-width:210px;margin-inline:auto}
  .hero .stats{gap:18px 26px;margin-top:34px;padding-top:22px}
  .hero .stats b{font-size:1.9rem}
  .hero .stats > div{flex:0 0 auto}
  /* One button in a phone hero, not two stacked full-width ones. The second action leads to
     the teacher gallery that begins one screen below and sits in the menu besides. */
  .hero .cta .btn-line{min-height:0;padding:6px 0;border:0;background:none;
    text-decoration:underline;text-underline-offset:5px}
}

/* The share row (31/08). Quiet until hovered; a partner's code rides along via site.js. */
.sharerow{display:flex;align-items:center;gap:9px;margin-top:22px;flex-wrap:wrap}
.sharerow > span{font-size:.68rem;font-weight:800;letter-spacing:.13em;text-transform:uppercase;
  color:var(--on-paper-3);margin-inline-end:2px}
.thero-txt .sharerow > span{color:var(--on-umber-3)}
.sharerow a,.sharerow button{display:inline-flex;align-items:center;justify-content:center;
  min-width:44px;min-height:44px;padding:0 12px;border-radius:100px;border:1px solid var(--hair-paper);
  background:none;color:inherit;font:inherit;font-size:.74rem;font-weight:800;letter-spacing:.06em;
  text-decoration:none;cursor:pointer;transition:border-color .2s,color .2s}
.thero-txt .sharerow a,.thero-txt .sharerow button{border-color:var(--hair-umber)}
.sharerow a:hover,.sharerow button:hover{border-color:var(--gold);color:var(--gold)}
.sharerow i{font-style:normal;font-size:.78rem;font-weight:700;color:var(--gold)}

/* The waitlist (01/09): intent collected while checkout waits on Paddle. The button shows
   only for a signed-in member -- site.js finds the session in storage and speaks REST
   directly, so 81 static pages stay free of the SDK. */
.waitbtn{margin-top:14px;min-height:48px;padding:0 22px;border-radius:100px;
  border:1px solid var(--hair-paper);background:none;color:inherit;font:inherit;
  font-size:.88rem;font-weight:800;cursor:pointer;transition:border-color .2s,color .2s}
.waitbtn:hover{border-color:var(--gold);color:var(--gold)}
.waitbtn.on{border-color:var(--gold);color:var(--gold)}

/* Reviews from owners (01/09). */
.rev-avg{color:var(--gold);font-weight:700;margin:0 0 22px}
.rev-avg i{font-style:normal;color:var(--on-paper-3);font-weight:500;font-size:.85rem}
.revs{display:flex;flex-direction:column;gap:14px}
.rev{margin:0;border:1px solid var(--hair-paper);border-radius:12px;padding:16px 18px;background:#fff2}
.rev-stars{color:var(--gold);letter-spacing:2px;font-size:.9rem}
.rev p{margin:8px 0;max-width:none}
.rev footer{font-size:.82rem;color:var(--on-paper-3);font-weight:700}
.rev footer a{color:inherit}

/* audit 03 H3 / 01: a finger needs 44px; on coarse pointers the language buttons grow, on a mouse they keep their size */
@media(pointer:coarse){ .langs a{min-height:44px;min-width:44px;display:inline-flex;align-items:center;justify-content:center} }


/* The handbook: a table of contents, and numbered steps a person can follow with one finger. */
.howto-toc{margin-top:34px;padding:20px 24px;border:1px solid var(--hair-paper);border-radius:16px;
  max-width:620px;background:color-mix(in srgb,var(--paper) 60%,transparent)}
.howto-toc b{display:block;font-size:.72rem;font-weight:800;letter-spacing:.16em;
  text-transform:uppercase;color:var(--gold);margin-bottom:10px}
.howto-toc ol{margin:0;padding-inline-start:20px;display:grid;gap:6px}
.howto-toc a{text-decoration:none;border-bottom:1px solid transparent}
.howto-toc a:hover{border-bottom-color:currentColor}
ol.howto{margin:0;padding-inline-start:26px;display:grid;gap:14px;counter-reset:none}
ol.howto li{padding-inline-start:6px;line-height:1.62;font-size:1rem}
ol.howto li::marker{color:var(--gold);font-weight:800}
.howto-note{margin:26px 0 0;padding:16px 20px;border-inline-start:3px solid var(--gold);
  border-radius:0 12px 12px 0;background:color-mix(in srgb,var(--gold) 8%,transparent);
  font-size:.95rem;line-height:1.6}
.howto-note b{font-weight:800;color:var(--gold)}
.room.umber .howto-toc{border-color:var(--hair-umber);background:transparent}
@media(max-width:720px){
  .howto-toc{padding:16px 18px}
  ol.howto{padding-inline-start:22px;gap:12px}
  ol.howto li{font-size:.96rem}
}
