1<!DOCTYPE html> 2<html lang="en"> 3<head> 4<meta charset="UTF-8" /> 5<meta name="viewport" content="width=device-width, initial-scale=1.0" /> 6<title>TheRecLab · Helping recruiters turn AI into real impact</title> 7<meta name="description" content="TheRecLab helps recruiting teams turn AI into real impact: hands-on workshops, 1:1 coaching, and RecOps consulting from a recruiter with 8 years and 300+ hires behind him." /> 8<meta name="theme-color" content="#161410" /> 9<meta property="og:type" content="website" /> 10<meta property="og:url" content="https://www.thereclab.ai/" /> 11<link rel="canonical" href="https://www.thereclab.ai/" /> 12<meta property="og:title" content="TheRecLab · Helping recruiters turn AI into real impact" /> 13<meta property="og:description" content="We help recruiting teams build automations and stop leaving value on the table with Claude and ChatGPT." /> 14<meta property="og:image" content="https://www.thereclab.ai/assets/og-image.jpg" /> 15<meta property="og:image:width" content="1200" /> 16<meta property="og:image:height" content="630" /> 17<meta name="twitter:card" content="summary_large_image" /> 18<meta name="twitter:title" content="TheRecLab · Helping recruiters turn AI into real impact" /> 19<meta name="twitter:description" content="We help recruiting teams build automations and stop leaving value on the table with Claude and ChatGPT." /> 20<meta name="twitter:image" content="https://www.thereclab.ai/assets/og-image.jpg" /> 21<link rel="icon" type="image/png" sizes="32x32" href="favicon-32.png?v=4" /> 22<link rel="icon" type="image/png" sizes="256x256" href="favicon.png?v=4" /> 23<link rel="apple-touch-icon" href="apple-touch-icon.png?v=4" /> 24<link rel="preconnect" href="https://fonts.googleapis.com" /> 25<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> 26<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Outfit:[email protected]&family=Schibsted+Grotesk:ital,wght@0,400..900;1,400..900&family=Newsreader:ital,opsz,wght@0,6..72,300..600;1,6..72,300..600&family=Space+Mono:wght@400;700&display=swap" rel="stylesheet" /> 27<link rel="preload" as="image" href="assets/workshop.jpg" fetchpriority="high" /> 28<style> 29 :root { 30 --ink: #1c1a16; 31 --ink-soft: #4a463e; 32 --paper: #f4efe6; 33 --paper-2: #ece4d6; 34 --terra: #e0a589; 35 --terra-deep: #c98a64; 36 --terra-soft: #e0a589; 37 --concrete: #8c8782; 38 --sage: #6c7860; 39 --sans: "Outfit", system-ui, sans-serif; 40 --display: "Schibsted Grotesk", system-ui, sans-serif; 41 --serif: "Instrument Serif", Georgia, serif; 42 --news: "Newsreader", Georgia, serif; 43 /* Two-curve motion voice: --ease for micro-interactions (hover, toggles), 44 --ease-out (expo) for entrances - fast arrival, long luxurious settle */ 45 --ease: cubic-bezier(.2,.7,.2,1); 46 --ease-out: cubic-bezier(.16,1,.3,1); 47 } 48 * { box-sizing: border-box; } 49 /* Body text uses Outfit (--sans); headings keep the Schibsted Grotesk display face */ 50 h1, h2, h3, h4 { --sans: var(--display); } 51 html { scroll-behavior: smooth; scroll-padding-top: 70px; } 52 html, body { margin: 0; padding: 0; } 53 body { font-family: var(--sans); color: var(--ink); } 54 html { background: #14110d; } 55 /* copy of the photo top behind the nav, sized to the hero's scale (116% = the 56 hero's cover width x 1.16) and left-anchored so the screen/pole edges line up. 57 Hero scrim is bottom-up, so the top is near-clear â no band darkening needed */ 58 body { background: url('assets/workshop.jpg') left top / 100% auto no-repeat, #14110d; } 59 ::selection { background: var(--terra); color: var(--ink); } 60 a:focus-visible, button:focus-visible { outline: 2px solid var(--terra); outline-offset: 3px; border-radius: 4px; } 61 .hero nav a { transition: color .25s var(--ease); } 62 .hero nav a:hover { color: #fff !important; } 63 footer a { transition: color .25s var(--ease); } 64 footer a:hover { color: #fff !important; } 65 .pill-btn { transition: transform .3s var(--ease), box-shadow .3s var(--ease); } 66 .pill-btn:hover { transform: translateY(-2px); box-shadow: 0 12px 26px -14px rgba(28,26,22,0.4); } 67 68 /* ---- Nav bar: transparent frosted glass, floats over the whole page ---- */ 69 .sticky-bar { position: sticky; top: 0; left: 0; right: 0; z-index: 1000; height: 66px; 70 display: flex; align-items: center; justify-content: space-between; padding: 0 40px; 71 background: rgba(26,22,18,0.40); 72 -webkit-backdrop-filter: blur(16px) saturate(1.3); backdrop-filter: blur(16px) saturate(1.3); 73 border-bottom: 1px solid rgba(255,255,255,0.14); 74 text-shadow: 0 1px 14px rgba(0,0,0,0.32); } 75 .sticky-bar nav a:hover { color: #fff !important; } 76 .hero { width: 100%; height: 100%; overflow: hidden; position: relative; font-family: var(--sans); } 77 .hero-wrap { height: calc(100vh - 66px); } 78 .build-card { transition: transform .3s var(--ease), box-shadow .3s var(--ease); } 79 .build-card:hover { transform: translateY(-5px); box-shadow: 0 28px 56px -26px rgba(28,26,22,0.38); } 80 .b-view { transition: transform .3s var(--ease); } 81 .build-card:hover .b-view { transform: translateX(4px); } 82 /* Testimonials: two-row auto marquee */ 83 @keyframes csScroll { from { transform: translateX(0); } to { transform: translateX(-50%); } } 84 .cs-marquee { display: flex; flex-direction: column; gap: 18px; 85 -webkit-mask-image: linear-gradient(to right, transparent, #000 5%, #000 95%, transparent); 86 mask-image: linear-gradient(to right, transparent, #000 5%, #000 95%, transparent); } 87 .cs-track { display: flex; gap: 18px; width: max-content; animation: csScroll 70s linear infinite; will-change: transform; } 88 .cs-track-rev { animation-direction: reverse; animation-duration: 86s; } 89 .cs-marquee:hover .cs-track { animation-play-state: paused; } 90 @media (prefers-reduced-motion: reduce) { .cs-track { animation: none; } .cs-marquee { overflow-x: auto; } } 91 .cs-swipe { display: none; } 92 /* Testimonials slider (desktop): one full testimonial per slide */ 93 .cs-slider { position: relative; max-width: 1160px; margin: 0 auto; } 94 .cs-slide-anim { animation: csFade .55s var(--ease-out) both; } 95 @keyframes csFade { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } } 96 .cs-arrow { position: absolute; top: 38%; transform: translateY(-50%); width: 46px; height: 46px; border-radius: 50%; 97 border: 1px solid rgba(255,255,255,0.25); background: rgba(20,16,12,0.5); -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); 98 color: #fff; cursor: pointer; display: flex; align-items: center; justify-content: center; z-index: 3; transition: background .2s, color .2s, border-color .2s; }
99 .cs-arrow:hover { background: var(--terra); color: var(--ink); border-color: var(--terra); } 100 .cs-prev { left: 0; } .cs-next { right: 0; } 101 .cs-dots { display: flex; gap: 9px; justify-content: center; margin-top: 28px; } 102 .cs-dot { width: 8px; height: 8px; padding: 0; border-radius: 50%; border: none; background: rgba(255,255,255,0.3); cursor: pointer; transition: background .2s, transform .2s; } 103 .cs-dot.on { background: var(--terra); transform: scale(1.35); } 104 /* Testimonial cards breathe on hover (pointer devices only) */ 105 @media (hover: hover) { 106 .cs-cell { transition: transform .5s var(--ease-out), box-shadow .5s var(--ease-out); } 107 .cs-cell:hover { transform: translateY(-4px); box-shadow: 0 22px 44px -24px rgba(28,26,22,0.35); } 108 } 109 .build-card > div:first-child { transition: transform .55s var(--ease); } 110 .build-card:hover > div:first-child { transform: scale(1.045); } 111 .hero img.bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; } 112 113 /* ---- Hero: parallax media wrapper + slow Ken Burns push-in ---- 114 Anchored to the top (parallax headroom lives at the bottom) and the zoom 115 origin pinned near the speaker so the push-in never crops his head. */ 116 .hero-media { position: absolute; left: 0; right: 0; top: 0; height: 100%; overflow: hidden; will-change: transform; background: #15110d; } 117 .hero-media img.bg { transform: scale(1.0); transform-origin: 0% 0%; } 118 .hero-content { will-change: transform, opacity; } 119 120 /* ---- Hero entrance choreography ---- */ 121 @keyframes hFade { from { opacity: 0; } to { opacity: 1; } } 122 @keyframes hRise { from { opacity: 0; transform: translateY(28px); } to { opacity: 1; transform: translateY(0); } } 123 @keyframes hlReveal { from { transform: translateY(115%); } to { transform: translateY(0); } } 124 .h-enter { opacity: 0; } 125 .h-nav { animation: hFade .9s var(--ease-out) .05s both; } 126 .h-sub { animation: hRise 1.1s var(--ease-out) .52s both; } 127 .hl-line { display: block; overflow: hidden; padding-bottom: .1em; margin-bottom: -.1em; } 128 .hl-inner { display: inline-block; transform: translateY(115%); animation: hlReveal 1.1s var(--ease-out) both; } 129 130 /* ---- Magnetic primary CTA ---- */ 131 .magnetic { position: relative; display: inline-block; will-change: transform; transition: transform .3s var(--ease); } 132 .magnetic-label { display: inline-block; will-change: transform; transition: transform .3s var(--ease); } 133 134 @media (prefers-reduced-motion: reduce) { 135 .hero-media img.bg { animation: none; transform: scale(1.0); } 136 .h-enter, .h-nav, .h-sub, .hl-inner { animation: none !important; opacity: 1 !important; transform: none !important; } 137 .sticky-bar { transition: none; } 138 html { scroll-behavior: auto; } 139 } 140 141 /* Tablet: keep the "practical things" grid at 2 columns */ 142 @media (min-width: 769px) and (max-width: 1280px) { 143 .practical-grid { grid-template-columns: repeat(2, 1fr) !important; } 144 } 145 146 /* Offering headings sit on one line on desktop; let them wrap below ~1024 */ 147 @media (max-width: 1023px) { 148 .offer-h3 { white-space: normal !important; } 149 } 150 /* Builds heading is wider; let it wrap below ~1100 */ 151 @media (max-width: 1100px) { 152 .builds-h2 { white-space: normal !important; } 153 } 154 /* Writing heading is wider still; let it wrap below ~1260 */ 155 @media (max-width: 1260px) { 156 .writing-h2 { white-space: normal !important; } 157 } 158 159 /* ============ MOBILE ============ */ 160 @media (max-width: 768px) { 161 html, body { overflow-x: hidden; } 162 /* Every multi-column grid collapses to a single column */ 163 [style*="grid-template-columns"] { grid-template-columns: 1fr !important; } 164 /* Bento / spanning cells reset so nothing creates implicit extra columns */ 165 [style*="grid-template-columns"] > * { grid-column: auto !important; grid-row: auto !important; } 166 /* Offerings: full-bleed colour bands, content inset, sub-items 2x2 */ 167 .offer-section { padding-left: 0 !important; padding-right: 0 !important; } 168 .offer-band { padding-left: 0 !important; padding-right: 0 !important; } 169 .offer-wrap { padding-left: 20px !important; padding-right: 20px !important; } 170 .bridge-lead { font-size: 24px !important; line-height: 1.32 !important; } 171 .bridge-sub { font-size: 17px !important; } 172 div.offer-items { grid-template-columns: 1fr 1fr !important; gap: 22px 16px !important; } 173 /* Reserve 2 lines for every step title so the body text lines up across all steps */ 174 .offer-items h4 { min-height: 42px !important; } 175 /* Card overlays open at the top (centering hides the heading above the fold on tall modals) */ 176 .ov-scrim { align-items: flex-start !important; padding: 14px !important; } 177 .faq-modal { padding: 30px 22px !important; } 178 .faq-modal h2 { font-size: 24px !important; } 179 .faq-steps { grid-template-columns: 1fr !important; } 180 .faq-step { border-left: none !important; padding: 22px 0 0 !important; } 181 .faq-step h3, .faq-step p { min-height: 0 !important; } 182 .faq-viz { height: auto !important; overflow: visible !important; } 183 /* Hiring Manager Enablement card + overlay */ 184 /* Uniform preview height for mockup cards; top-aligned with a soft bottom fade so long mockups don't clip harshly */ 185 .build-card .hm-front { aspect-ratio: auto !important; height: 200px !important; align-items: flex-start !important; padding: 16px 14px 0 !important; -webkit-mask-image: linear-gradient(180deg, #000 70%, transparent) !important; mask-image: linear-gradient(180deg, #000 70%, transparent) !important; } 186 .hm-cols { flex-direction: column !important; gap: 26px !important; } 187 .hm-cols > div { height: auto !important; overflow: visible !important; -webkit-mask-image: none !important; mask-image: none !important; } 188 .hm-modal { padding: 30px 20px !important; } 189 .hm-modal h2 { font-size: 22px !important; } 190 .mkt-modal h2 { font-size: 22px !important; } 191 .mkt-modal > div { padding-left: 20px !important; padding-right: 20px !important; } 192 .vibe-modal { padding: 26px 20px !important; } 193 .vibe-modal h2 { font-size: 24px !important; } 194 .vibe-cols { flex-direction: column !important; gap: 22px !important; align-items: stretch !important; } 195 .closing-row { flex-direction: column !important; align-items: stretch !important; gap: 28px !important; } 196 .closing-row > div:first-child { flex: none !important; max-width: 100% !important; } 197 /* Tame the fixed desktop padding on section wrappers */ 198 section, footer { padding-left: 20px !important; padding-right: 20px !important; } 199 section > div, footer > div { padding-left: 4px !important; padding-right: 4px !important; } 200 /* Big fixed headings scale down */ 201 [style*="font-size: 54px"] { font-size: 30px !important; line-height: 1.12 !important; } 202 [style*="font-size: 60px"] { font-size: 32px !important; line-height: 1.12 !important; } 203 /* Hero */ 204 .hero-content { padding: 40px 22px 40px !important; } 205 .hero-content nav { display: none !important; } 206 .sticky-bar { height: 56px !important; padding: 0 20px !important; } 207 .sticky-bar nav { display: none !important; } 208 .hero-wrap { height: calc(100vh - 56px) !important; height: calc(100svh - 56px) !important; } 209 /* mobile hero uses a different crop; keep a simple flat band behind the nav */ 210 body { background: linear-gradient(#bfbbb2,#bfbbb2) left top / 100% 56px no-repeat, #14110d !important; } 211 /* Hero text sits at the bottom on mobile */ 212 .hero-textblock { margin-top: auto !important; margin-bottom: 0 !important; } 213 /* Proof band: darker scrim on mobile so the stat reads over the photo */ 214 .proof-scrim { background: linear-gradient(to bottom, rgba(14,12,10,0.86) 0%, rgba(14,12,10,0.6) 45%, rgba(14,12,10,0.72) 100%) !important; } 215 /* Reframe the photo on mobile: shift the crop toward Jamie's side (moves him 216 right) and anchor the zoom at the top (drops his face lower, clear of logo) */ 217 .hero-media img.bg { animation: none !important;
217 object-position: 38% top !important; transform: scale(1.0) !important; transform-origin: 50% 0% !important; } 218 /* Founder photo: give the frame a definite height so the image fills it 219 (div.founder-frame beats the [style*="height: 440px"] rule below) */ 220 /* padding:0 undoes the [style*="px 80px"] rule that the frame's box-shadow 221 ("40px 80px") accidentally matches - it was leaving a gap above the photo */ 222 div.founder-frame { height: 420px !important; min-height: 0 !important; padding: 0 !important; } 223 div.founder-frame img { height: 420px !important; } 224 .hero-headline { font-size: 32px !important; line-height: 1.1 !important; text-wrap: wrap !important; white-space: normal !important; } 225 .hero-headline .hl-line, .hero-headline .hl-inner { white-space: normal !important; overflow: visible !important; } 226 .h-sub { font-size: 16px !important; } 227 /* Tighten big section gaps that were tuned for desktop */ 228 [style*="gap: 80px"], [style*="gap: 88px"], [style*="gap: 72px"] { gap: 36px !important; } 229 /* Tighter vertical rhythm on the big section containers (gaps were ~2x too big) */ 230 [style*="px 80px"] { padding-top: 26px !important; padding-bottom: 28px !important; } 231 [style*="margin-bottom: 112px"] { margin-bottom: 40px !important; } 232 [style*="gap: 96px"] { gap: 40px !important; } 233 /* Repetitive card rows become horizontal swipe carousels (no more endless scroll) */ 234 .cs-grid, .b-cards { 235 display: flex !important; 236 flex-wrap: nowrap !important; 237 overflow-x: auto; 238 scroll-snap-type: x mandatory; 239 -webkit-overflow-scrolling: touch; 240 gap: 14px !important; 241 padding-bottom: 14px !important; 242 scrollbar-width: none; 243 } 244 .cs-grid::-webkit-scrollbar, .b-cards::-webkit-scrollbar { display: none; } 245 .cs-grid > *, .b-cards > * { flex: 0 0 84% !important; scroll-snap-align: center; } 246 /* Scroll-progress slider under each carousel */ 247 .carousel-indicator { width: 72px; height: 4px; margin: 18px auto 0; border-radius: 100px; background: rgba(28,26,22,0.12); overflow: hidden; } 248 .carousel-indicator-thumb { height: 100%; border-radius: 100px; background: var(--terra); transition: transform .14s ease-out; } 249 /* Shorter featured build-card media on mobile so cards aren't overly tall */ 250 [style*="height: 440px"] { height: 200px !important; } 251 /* Build cards: clamp the body copy so cards aren't overly tall */ 252 .b-desc { display: -webkit-box !important; -webkit-line-clamp: 4 !important; -webkit-box-orient: vertical !important; overflow: hidden !important; } 253 /* Testimonials: hide the desktop auto-marquee, show a single swipe carousel like Builds */ 254 .cs-marquee, .cs-slider { display: none !important; } 255 .cs-swipe { 256 display: flex !important; 257 flex-wrap: nowrap !important; 258 overflow-x: auto; 259 scroll-snap-type: x mandatory; 260 -webkit-overflow-scrolling: touch; 261 gap: 14px !important; 262 padding-bottom: 14px !important; 263 scrollbar-width: none; 264 } 265 .cs-swipe::-webkit-scrollbar { display: none; } 266 /* taller cards so the section fills the space; one card ~84% wide */ 267 .cs-swipe > .cs-mcard { flex: 0 0 84% !important; scroll-snap-align: center; min-height: 300px; } 268 .cs-swipe + .carousel-indicator { background: rgba(255,255,255,0.22); } 269 } 270 @media (max-width: 420px) { 271 .hero-headline { font-size: 27px !important; } 272 [style*="font-size: 54px"], [style*="font-size: 60px"] { font-size: 26px !important; } 273 } 274</style> 275</head> 276<body> 277<div id="root"></div> 278
279<script src="https://unpkg.com/[email protected]/umd/react.production.min.js" integrity="sha384-DGyLxAyjq0f9SPpVevD6IgztCFlnMF6oW/XQGmfe+IsZ8TqEiDrcHkMLKI6fiB/Z" crossorigin="anonymous"></script>
vendor: 1 bytes, line 279
279
280<script src="https://unpkg.com/[email protected]/umd/react-dom.production.min.js" integrity="sha384-gTGxhz21lVGYNMcdJOyq01Edg0jhn/c22nsx0kyqP0TxaV5WVdsSH1fSDUf5YJj1" crossorigin="anonymous"></script>
vendor: 1 bytes, line 280
280
281<script src="https://unpkg.com/@babel/[email protected]/babel.min.js" integrity="sha384-m08KidiNqLdpJqLq95G/LEi8Qvjl/xUYll3QILypMoQ65QorJ9Lvtp2RXYGBFj1y" crossorigin="anonymous"></script>
vendor: 1 bytes, line 281
281
282<script src="scroll-reveal.js"></script>
vendor: 1 bytes, line 282
282
283<script src="motion.js"></script>
vendor: 1 bytes, line 283
283
284<script src="carousel-indicator.js"></script>
vendor: 1 bytes, line 284
284
285<script type="text/babel" src="heroes.jsx"></script>
vendor: 1 bytes, line 285
285
286<script type="text/babel" src="offerings.jsx"></script>
vendor: 1 bytes, line 286
286
287<script type="text/babel" src="proof.jsx"></script>
vendor: 1 bytes, line 287
287
288<script type="text/babel" src="about.jsx"></script>
vendor: 1 bytes, line 288
288
289<script type="text/babel" src="casestudies.jsx"></script>
vendor: 1 bytes, line 289
289
290<script type="text/babel" src="builds.jsx"></script>
vendor: 1 bytes, line 290
290
291<script type="text/babel" src="blog.jsx"></script>
vendor: 1 bytes, line 291
291
292<script type="text/babel" src="contact.jsx"></script>
vendor: 1 bytes, line 292
292
293<script type="text/babel"> 294 const H = window.RecLabHeroes; 295 const O = window.RecLabOfferings; 296 const PR = window.RecLabProof; 297 const A = window.RecLabAbout; 298 const CS = window.RecLabCases; 299 const B = window.RecLabBuilds; 300 const BL = window.RecLabBlog; 301 const C = window.RecLabContact; 302 const IMG = "assets/workshop.jpg"; 303 304 function App() { 305 React.useEffect(() => { 306 window.initScrollReveal && window.initScrollReveal(); 307 window.initMotion && window.initMotion(); 308 window.initCarouselIndicators && window.initCarouselIndicators(); 309 }, []); 310 return ( 311 <div> 312 <H.StickyBar /> 313 <div className="hero-wrap"><H.FullBleed img={IMG} imgMobile="assets/workshop-mobile.jpg" /></div> 314 <O.Offerings /> 315 <CS.CaseStudies /> 316 <B.Builds /> 317 <A.About /> 318 <BL.CardRow /> 319 <C.Contact /> 320 <C.Footer /> 321 </div> 322 ); 323 } 324 ReactDOM.createRoot(document.getElementById("root")).render(<App />); 325</script>
325 326</body> 327</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.