// ig-illustrations.jsx — 1518.coffee Instagram · visual system
// Origin landscapes, bean botanicals, gear line art.
// Extends the timer's TERRAIN system into full-bleed IG backgrounds.
// Needs shared.jsx + ig-system.jsx loaded first.

// ════════════════════════════════════════════════════════════
// ORIGIN LANDSCAPES — full-bleed terrain scenes
// Re-uses brew-timer's terrain vocabulary but richer:
// 3 layered ridges + mist + stars/particles + dawn/dusk sky.
// ════════════════════════════════════════════════════════════

const IG_TERRAIN_FULL = {
  andes: [
    'M0,180 L45,125 95,175 150,108 205,180 260,106 320,175 365,122 400,162 L400,400 0,400Z',
    'M0,230 L70,191 140,233 205,181 265,230 330,187 400,225 L400,400 0,400Z',
    'M0,290 L80,263 160,293 230,259 305,290 360,265 400,285 L400,400 0,400Z',
  ],
  volcanic: [
    'M0,231 L66,231 184,131 197,143 210,131 326,231 400,231 L400,400 0,400Z',
    'M0,277 L36,277 120,199 135,211 150,199 244,277 400,277 L400,400 0,400Z',
    'M0,321 L80,305 160,322 240,301 320,320 400,310 L400,400 0,400Z',
  ],
  plateau: [
    'M0,185 L70,181 86,157 250,153 268,181 400,177 L400,400 0,400Z',
    'M0,241 L132,236 148,213 322,209 342,238 400,234 L400,400 0,400Z',
    'M0,295 L90,290 200,295 310,288 400,293 L400,400 0,400Z',
  ],
  hills: [
    'M0,215 Q70,183 140,213 Q210,243 280,213 Q342,187 400,213 L400,400 0,400Z',
    'M0,267 Q80,236 160,265 Q240,293 320,265 Q362,247 400,265 L400,400 0,400Z',
    'M0,319 Q70,295 140,317 Q210,337 280,317 Q352,297 400,317 L400,400 0,400Z',
  ],
  peak: [
    'M0,237 L120,231 210,123 300,231 400,235 L400,400 0,400Z',
    'M0,277 L110,271 222,225 300,275 400,277 L400,400 0,400Z',
    'M0,321 L90,306 180,322 270,304 360,320 400,312 L400,400 0,400Z',
  ],
};

const IG_ARCH_SIG = {
  andes:    { skyA:'#705E46', skyB:'#262820', ridges:['#3E4A38','#34402E','#2A3526'], mist:'#8FA07E', mistAmt:.45 },
  volcanic: { skyA:'#6C5A4C', skyB:'#23272A', ridges:['#3D4640','#333B35','#29302B'], mist:'#94A099', mistAmt:.55 },
  plateau:  { skyA:'#766140', skyB:'#2A271E', ridges:['#4E4732','#413B29','#332F21'], mist:'#AC9A6E', mistAmt:.35 },
  hills:    { skyA:'#6E6342', skyB:'#25261B', ridges:['#46492F','#3B3E27','#2F3320'], mist:'#9AA274', mistAmt:.4 },
  peak:     { skyA:'#695C50', skyB:'#212729', ridges:['#3B4748','#313C3E','#293233'], mist:'#94A4A6', mistAmt:.5, snow:true },
};

function IGLandscape({ terrain='andes', placement='full', opacity=1 }){
  const P = useP();
  const paths = IG_TERRAIN_FULL[terrain] || IG_TERRAIN_FULL.andes;
  const sig = IG_ARCH_SIG[terrain] || IG_ARCH_SIG.andes;
  const uid = 'igl-'+terrain+'-'+Math.random().toString(36).slice(2,6);

  // placement: 'full' (entire frame), 'upper' (top 55%), 'lower' (bottom 55%)
  const posStyle = placement === 'upper'
    ? { top:0, left:0, right:0, height:'55%' }
    : placement === 'lower'
    ? { bottom:0, left:0, right:0, height:'55%' }
    : { inset:0 };

  return (
    <div aria-hidden style={{ position:'absolute', ...posStyle, overflow:'hidden', opacity, pointerEvents:'none' }}>
      <svg viewBox="0 0 400 400" preserveAspectRatio="xMidYMax slice"
        style={{ position:'absolute', inset:0, width:'100%', height:'100%' }}>
        <defs>
          <linearGradient id={uid+'sky'} x1="0" y1="0" x2="0" y2="1">
            <stop offset="0%" stopColor={sig.skyA} /><stop offset="100%" stopColor={sig.skyB} />
          </linearGradient>
        </defs>
        <rect width="400" height="400" fill={`url(#${uid}sky)`} />
        {/* stars / dust particles */}
        {[
          [68,42],[142,58],[210,35],[288,66],[340,28],[52,80],[182,90],[310,50],[380,72],[120,25],
          [250,48],[44,55],[170,68],[330,82],[90,38],[260,22],[160,15],[350,45],[75,62],[225,75],
        ].map(([x,y],k)=>(
          <circle key={k} cx={x} cy={y} r={k%3===0?1.2:0.7} fill="#F4ECDD"
            opacity={0.12 + (k%5)*0.06} />
        ))}
        {/* mist band */}
        <ellipse cx="200" cy="227" rx="260" ry="30" fill={sig.mist} opacity={sig.mistAmt} />
        <ellipse cx="120" cy="275" rx="200" ry="22" fill={sig.mist} opacity={sig.mistAmt*0.7} />
        {/* three ridge layers */}
        {paths.map((d,k)=><path key={k} d={d} fill={sig.ridges[k]} />)}
        {/* stroke highlight on back ridge */}
        <path d={paths[0]} fill="none" stroke={sig.mist} strokeWidth="0.8" opacity="0.2" />
        {/* snow cap */}
        {sig.snow && <path d="M210,123 L228,159 196,159Z" fill="#D9D2C4" opacity="0.75" />}
      </svg>
    </div>
  );
}


// ════════════════════════════════════════════════════════════
// BEAN BOTANICALS — stylized line art
// Coffee cherry, green bean cross-section, roasted bean.
// Warm stroke on dark. Meant to float as background elements.
// ════════════════════════════════════════════════════════════

function BeanCherry({ size=200, color='#E26F38', opacity=0.18, style={} }){
  return (
    <svg width={size} height={size} viewBox="0 0 120 120" fill="none" style={{ display:'block', ...style }}>
      {/* cherry body */}
      <ellipse cx="60" cy="62" rx="28" ry="30" stroke={color} strokeWidth="1.5" opacity={opacity} />
      <ellipse cx="60" cy="62" rx="20" ry="22" stroke={color} strokeWidth="0.8" opacity={opacity*0.7} />
      {/* stem */}
      <path d="M60 32 Q58 18 52 10" stroke={color} strokeWidth="1.3" strokeLinecap="round" opacity={opacity} />
      <path d="M52 10 Q48 6 42 8" stroke={color} strokeWidth="1.3" strokeLinecap="round" opacity={opacity*0.8} />
      {/* leaf */}
      <path d="M42 8 Q32 14 36 26 Q44 22 50 12 Q46 8 42 8Z" stroke={color} strokeWidth="1" opacity={opacity*0.6} />
      {/* vein on leaf */}
      <path d="M42 10 Q38 18 38 22" stroke={color} strokeWidth="0.6" opacity={opacity*0.4} />
      {/* seed line */}
      <path d="M60 42 Q56 62 60 82" stroke={color} strokeWidth="0.8" opacity={opacity*0.5} strokeLinecap="round" />
    </svg>
  );
}

function BeanRoasted({ size=160, color='#E26F38', opacity=0.18, style={} }){
  return (
    <svg width={size} height={size} viewBox="0 0 100 100" fill="none" style={{ display:'block', ...style }}>
      {/* bean body */}
      <ellipse cx="50" cy="50" rx="24" ry="30" stroke={color} strokeWidth="1.5" opacity={opacity}
        transform="rotate(-12 50 50)" />
      {/* center crease */}
      <path d="M50 24 Q44 38 46 50 Q48 62 50 76" stroke={color} strokeWidth="1.2" opacity={opacity*0.8}
        strokeLinecap="round" />
      {/* subtle surface lines */}
      <path d="M38 36 Q42 40 40 48" stroke={color} strokeWidth="0.6" opacity={opacity*0.4} strokeLinecap="round" />
      <path d="M62 54 Q58 60 60 68" stroke={color} strokeWidth="0.6" opacity={opacity*0.4} strokeLinecap="round" />
    </svg>
  );
}

function BeanCrossSection({ size=180, color='#E26F38', opacity=0.18, style={} }){
  return (
    <svg width={size} height={size} viewBox="0 0 110 110" fill="none" style={{ display:'block', ...style }}>
      {/* outer skin */}
      <circle cx="55" cy="55" r="32" stroke={color} strokeWidth="1.5" opacity={opacity} />
      {/* mucilage layer */}
      <circle cx="55" cy="55" r="26" stroke={color} strokeWidth="0.8" opacity={opacity*0.6} strokeDasharray="4 3" />
      {/* parchment */}
      <circle cx="55" cy="55" r="20" stroke={color} strokeWidth="1" opacity={opacity*0.7} />
      {/* two seed halves */}
      <path d="M55 35 Q42 45 42 55 Q42 65 55 75" stroke={color} strokeWidth="1.2" opacity={opacity*0.8} strokeLinecap="round" />
      <path d="M55 35 Q68 45 68 55 Q68 65 55 75" stroke={color} strokeWidth="1.2" opacity={opacity*0.8} strokeLinecap="round" />
      {/* center line */}
      <line x1="55" y1="37" x2="55" y2="73" stroke={color} strokeWidth="0.8" opacity={opacity*0.5} />
      {/* labels — concentric rings */}
      <circle cx="55" cy="55" r="38" stroke={color} strokeWidth="0.4" opacity={opacity*0.3} strokeDasharray="2 6" />
    </svg>
  );
}

function BeanScatter({ count=5, color='#E26F38', opacity=0.12, area={x:0,y:0,w:640,h:800} }){
  // scattered roasted beans at various rotations — decorative fill
  const seeds = React.useMemo(()=>{
    const out = [];
    for(let i=0;i<count;i++){
      out.push({
        x: area.x + (area.w * (0.1 + 0.8 * ((i*0.618)%1))),
        y: area.y + (area.h * (0.08 + 0.84 * ((i*0.382+0.1)%1))),
        rot: (i*73)%360,
        s: 0.6 + (i%3)*0.25,
      });
    }
    return out;
  },[count, area.x, area.y, area.w, area.h]);

  return (
    <div aria-hidden style={{ position:'absolute', inset:0, pointerEvents:'none' }}>
      {seeds.map((b,k)=>(
        <div key={k} style={{ position:'absolute', left:b.x, top:b.y,
          transform:`rotate(${b.rot}deg) scale(${b.s})`, transformOrigin:'center' }}>
          <BeanRoasted size={80} color={color} opacity={opacity} />
        </div>
      ))}
    </div>
  );
}


// ════════════════════════════════════════════════════════════
// GEAR LINE ART — clean, architectural drawings
// V60, Chemex, AeroPress, gooseneck kettle, grinder, scale.
// Single-color stroke. Float as background or hero element.
// ════════════════════════════════════════════════════════════

function GearV60({ size=200, color='#E26F38', opacity=0.22, style={} }){
  return (
    <svg width={size} height={size} viewBox="0 0 120 140" fill="none" style={{ display:'block', ...style }}>
      {/* cone body */}
      <path d="M28 28 L92 28 L72 100 L48 100Z" stroke={color} strokeWidth="1.5" opacity={opacity}
        strokeLinejoin="round" />
      {/* ridges inside */}
      <path d="M38 36 L52 92" stroke={color} strokeWidth="0.6" opacity={opacity*0.4} />
      <path d="M48 34 L56 90" stroke={color} strokeWidth="0.6" opacity={opacity*0.4} />
      <path d="M58 34 L60 90" stroke={color} strokeWidth="0.6" opacity={opacity*0.4} />
      <path d="M68 34 L64 90" stroke={color} strokeWidth="0.6" opacity={opacity*0.4} />
      <path d="M78 36 L68 92" stroke={color} strokeWidth="0.6" opacity={opacity*0.4} />
      {/* handle tab */}
      <path d="M92 28 Q102 30 100 42 Q98 52 88 50" stroke={color} strokeWidth="1.2" opacity={opacity*0.8}
        strokeLinecap="round" />
      {/* server / mug below */}
      <path d="M36 102 L36 124 Q36 130 42 130 L78 130 Q84 130 84 124 L84 102"
        stroke={color} strokeWidth="1.3" opacity={opacity*0.7} strokeLinecap="round" />
      {/* drip hole */}
      <circle cx="60" cy="100" r="3" stroke={color} strokeWidth="0.8" opacity={opacity*0.5} />
      {/* coffee level in server */}
      <path d="M40 118 Q60 114 80 118" stroke={color} strokeWidth="0.7" opacity={opacity*0.35} />
    </svg>
  );
}

function GearChemex({ size=200, color='#E26F38', opacity=0.22, style={} }){
  return (
    <svg width={size} height={size} viewBox="0 0 100 150" fill="none" style={{ display:'block', ...style }}>
      {/* upper funnel */}
      <path d="M22 10 L78 10 L56 62 L44 62Z" stroke={color} strokeWidth="1.5" opacity={opacity}
        strokeLinejoin="round" />
      {/* waist / collar */}
      <path d="M44 62 Q42 68 44 74 L56 74 Q58 68 56 62" stroke={color} strokeWidth="1.3" opacity={opacity*0.8} />
      {/* collar band (wood) */}
      <path d="M42 64 Q50 66 58 64" stroke={color} strokeWidth="2" opacity={opacity*0.6} strokeLinecap="round" />
      <path d="M42 72 Q50 70 58 72" stroke={color} strokeWidth="2" opacity={opacity*0.6} strokeLinecap="round" />
      {/* tie */}
      <circle cx="42" cy="68" r="2" stroke={color} strokeWidth="0.8" opacity={opacity*0.5} />
      {/* lower body */}
      <path d="M44 74 L30 126 Q28 136 38 138 L62 138 Q72 136 70 126 L56 74"
        stroke={color} strokeWidth="1.5" opacity={opacity} strokeLinejoin="round" />
      {/* coffee level */}
      <path d="M36 120 Q50 116 64 120" stroke={color} strokeWidth="0.7" opacity={opacity*0.35} />
      {/* spout channel */}
      <path d="M22 10 Q18 8 16 12 L16 16 Q16 20 22 18" stroke={color} strokeWidth="1" opacity={opacity*0.6} strokeLinecap="round" />
    </svg>
  );
}

function GearAeropress({ size=200, color='#E26F38', opacity=0.22, style={} }){
  return (
    <svg width={size} height={size} viewBox="0 0 80 150" fill="none" style={{ display:'block', ...style }}>
      {/* chamber */}
      <rect x="18" y="30" width="44" height="80" rx="3" stroke={color} strokeWidth="1.5" opacity={opacity} />
      {/* plunger */}
      <rect x="22" y="8" width="36" height="6" rx="3" stroke={color} strokeWidth="1.2" opacity={opacity*0.7} />
      <line x1="40" y1="14" x2="40" y2="30" stroke={color} strokeWidth="1.2" opacity={opacity*0.6} />
      <path d="M24 28 L56 28" stroke={color} strokeWidth="1.5" opacity={opacity*0.8} />
      {/* rubber seal */}
      <path d="M22 46 L58 46" stroke={color} strokeWidth="2" opacity={opacity*0.5} />
      {/* graduation marks */}
      {[55,65,75,85,95].map((y,k)=>(
        <React.Fragment key={k}>
          <line x1="20" y1={y} x2="26" y2={y} stroke={color} strokeWidth="0.5" opacity={opacity*0.3} />
        </React.Fragment>
      ))}
      {/* filter cap */}
      <path d="M18 110 L18 118 Q18 124 24 124 L56 124 Q62 124 62 118 L62 110"
        stroke={color} strokeWidth="1.3" opacity={opacity*0.7} strokeLinecap="round" />
      {/* filter dots */}
      {[30,36,42,48,54].map((x,k)=>(
        <circle key={k} cx={x} cy="117" r="1" fill={color} opacity={opacity*0.3} />
      ))}
      {/* drip */}
      <line x1="40" y1="124" x2="40" y2="136" stroke={color} strokeWidth="0.8" opacity={opacity*0.3} strokeDasharray="2 3" />
      {/* cup */}
      <path d="M30 136 L30 146 Q30 148 34 148 L46 148 Q50 148 50 146 L50 136"
        stroke={color} strokeWidth="1" opacity={opacity*0.5} />
    </svg>
  );
}

function GearKettle({ size=200, color='#E26F38', opacity=0.22, style={} }){
  return (
    <svg width={size} height={size} viewBox="0 0 130 120" fill="none" style={{ display:'block', ...style }}>
      {/* body */}
      <path d="M30 40 Q30 28 45 24 L85 24 Q100 28 100 40 L100 80 Q100 96 85 100 L45 100 Q30 96 30 80Z"
        stroke={color} strokeWidth="1.5" opacity={opacity} />
      {/* gooseneck spout */}
      <path d="M30 48 Q16 44 12 36 Q8 26 14 18 Q18 12 24 14"
        stroke={color} strokeWidth="1.5" opacity={opacity*0.8} strokeLinecap="round" />
      {/* spout opening */}
      <circle cx="22" cy="14" r="3" stroke={color} strokeWidth="0.8" opacity={opacity*0.5} />
      {/* handle */}
      <path d="M100 38 Q116 42 118 60 Q118 78 100 82"
        stroke={color} strokeWidth="1.5" opacity={opacity*0.8} strokeLinecap="round" />
      {/* lid */}
      <path d="M42 24 L88 24" stroke={color} strokeWidth="1.8" opacity={opacity*0.6} />
      <path d="M58 24 Q60 18 62 18 Q64 18 66 24" stroke={color} strokeWidth="1" opacity={opacity*0.5} />
      {/* base */}
      <path d="M34 100 L96 100 Q100 100 100 104 L100 108 Q100 110 96 110 L34 110 Q30 110 30 108 L30 104 Q30 100 34 100Z"
        stroke={color} strokeWidth="1" opacity={opacity*0.5} />
      {/* temp display */}
      <rect x="52" y="54" width="26" height="14" rx="3" stroke={color} strokeWidth="0.8" opacity={opacity*0.35} />
    </svg>
  );
}

function GearGrinder({ size=200, color='#E26F38', opacity=0.22, style={} }){
  return (
    <svg width={size} height={size} viewBox="0 0 90 140" fill="none" style={{ display:'block', ...style }}>
      {/* hopper top */}
      <path d="M20 12 L70 12 L62 36 L28 36Z" stroke={color} strokeWidth="1.5" opacity={opacity} strokeLinejoin="round" />
      {/* body */}
      <rect x="24" y="36" width="42" height="60" rx="4" stroke={color} strokeWidth="1.5" opacity={opacity} />
      {/* burr indicator */}
      <circle cx="45" cy="52" r="8" stroke={color} strokeWidth="0.8" opacity={opacity*0.5} />
      <circle cx="45" cy="52" r="3" fill={color} opacity={opacity*0.3} />
      {/* adjustment ring */}
      <path d="M28 44 L62 44" stroke={color} strokeWidth="0.8" opacity={opacity*0.4} />
      {/* grind setting dots */}
      {[34,39,44,49,54,59].map((x,k)=>(
        <circle key={k} cx={x} cy="41" r="0.8" fill={color} opacity={opacity*0.3} />
      ))}
      {/* catch cup */}
      <path d="M22 96 L22 120 Q22 128 30 128 L60 128 Q68 128 68 120 L68 96"
        stroke={color} strokeWidth="1.3" opacity={opacity*0.7} strokeLinecap="round" />
      {/* ground line */}
      <path d="M28 116 Q45 112 62 116" stroke={color} strokeWidth="0.7" opacity={opacity*0.3} />
    </svg>
  );
}

function GearScale({ size=200, color='#E26F38', opacity=0.22, style={} }){
  return (
    <svg width={size} height={size} viewBox="0 0 130 80" fill="none" style={{ display:'block', ...style }}>
      {/* platform */}
      <rect x="10" y="8" width="110" height="8" rx="4" stroke={color} strokeWidth="1.5" opacity={opacity} />
      {/* body */}
      <path d="M18 16 L112 16 L108 56 Q108 62 102 62 L28 62 Q22 62 22 56Z"
        stroke={color} strokeWidth="1.5" opacity={opacity} />
      {/* display */}
      <rect x="38" y="28" width="54" height="20" rx="4" stroke={color} strokeWidth="1" opacity={opacity*0.6} />
      {/* readout */}
      <line x1="48" y1="38" x2="56" y2="38" stroke={color} strokeWidth="1.5" opacity={opacity*0.4} />
      <line x1="60" y1="34" x2="60" y2="42" stroke={color} strokeWidth="0.6" opacity={opacity*0.3} />
      <line x1="64" y1="38" x2="72" y2="38" stroke={color} strokeWidth="1.5" opacity={opacity*0.4} />
      <line x1="76" y1="38" x2="82" y2="38" stroke={color} strokeWidth="1.5" opacity={opacity*0.4} />
      {/* buttons */}
      <circle cx="34" cy="52" r="4" stroke={color} strokeWidth="0.8" opacity={opacity*0.4} />
      <circle cx="96" cy="52" r="4" stroke={color} strokeWidth="0.8" opacity={opacity*0.4} />
      {/* feet */}
      <circle cx="26" cy="65" r="3" stroke={color} strokeWidth="0.8" opacity={opacity*0.3} />
      <circle cx="104" cy="65" r="3" stroke={color} strokeWidth="0.8" opacity={opacity*0.3} />
    </svg>
  );
}


// ════════════════════════════════════════════════════════════
// COMPOSED TEMPLATES — templates + illustrations
// ════════════════════════════════════════════════════════════

// Origin post with full landscape background
function TplOriginLandscape({ w=640, h=800, country, terrain='andes', data, note }){
  const P = useP();
  return (
    <IGFrame w={w} h={h} light>
      <IGLandscape terrain={terrain} placement="full" opacity={0.85} />
      {/* heavy scrim from bottom */}
      <div style={{ position:'absolute', inset:0, zIndex:2,
        background:'linear-gradient(to top, #211B16 0%, #211B16ee 25%, #211B16aa 45%, transparent 68%)' }} />
      <div style={{ position:'absolute', inset:0, display:'flex', flexDirection:'column',
        justifyContent:'flex-end', padding:'48px 44px 56px', zIndex:3 }}>
        <IGLabel color="#E26F38" style={{ marginBottom:10 }}>The Origin</IGLabel>
        <div className="serif" style={{ fontSize:46, lineHeight:1.05, color:'#F4ECDD',
          letterSpacing:'-0.02em' }}>{country}</div>
        {data && <div style={{ marginTop:20 }}>
          {data.map((r,k)=>(
            <div key={k} style={{ display:'flex', justifyContent:'space-between', alignItems:'baseline',
              padding:'8px 0', borderBottom: k<data.length-1 ? '1px solid rgba(244,236,221,0.12)' : 'none' }}>
              <span className="sans" style={{ fontSize:10, fontWeight:600, letterSpacing:'0.14em',
                textTransform:'uppercase', color:'#9E9079' }}>{r.label}</span>
              <span className="serif" style={{ fontSize:16, color:'#F4ECDD' }}>{r.value}</span>
            </div>
          ))}
        </div>}
        {note && <div className="serif" style={{ fontStyle:'italic', fontSize:15, color:'#D6C9B4',
          marginTop:14, lineHeight:1.45 }}>{note}</div>}
      </div>
    </IGFrame>
  );
}

// Bean-focused post — botanical art background
function TplBeanCard({ w=640, h=800, eyebrow, title, sub, variant='cherry' }){
  const P = useP();
  const BG = variant === 'cherry' ? BeanCherry : variant === 'cross' ? BeanCrossSection : BeanRoasted;
  return (
    <IGFrame w={w} h={h}>
      {/* large background botanical */}
      <div style={{ position:'absolute', top:'8%', right:'-12%', opacity:0.6, pointerEvents:'none' }}>
        <BG size={420} color={P.sage} opacity={0.14} />
      </div>
      <div style={{ position:'absolute', bottom:'15%', left:'-8%', opacity:0.4, pointerEvents:'none',
        transform:'rotate(25deg)' }}>
        <BG size={280} color={P.sage} opacity={0.1} />
      </div>
      <div style={{ position:'absolute', inset:0, display:'flex', flexDirection:'column',
        justifyContent:'center', padding:'60px 48px', zIndex:2 }}>
        {eyebrow && <IGLabel style={{ marginBottom:18 }}>{eyebrow}</IGLabel>}
        <div className="serif" style={{ fontSize:38, lineHeight:1.15, color:P.ink,
          letterSpacing:'-0.015em' }}>{title}</div>
        {sub && <div className="serif" style={{ fontStyle:'italic', fontSize:19, color:P.stone,
          marginTop:16, lineHeight:1.45 }}>{sub}</div>}
      </div>
    </IGFrame>
  );
}

// Gear-focused post — equipment line art as hero
function TplGearCard({ w=640, h=800, eyebrow, title, sub, gear='v60' }){
  const P = useP();
  const GEAR_MAP = { v60:GearV60, chemex:GearChemex, aeropress:GearAeropress, kettle:GearKettle, grinder:GearGrinder, scale:GearScale };
  const GearComp = GEAR_MAP[gear] || GearV60;
  return (
    <IGFrame w={w} h={h}>
      {/* large hero gear illustration */}
      <div style={{ position:'absolute', top:'10%', left:'50%', transform:'translateX(-50%)', pointerEvents:'none' }}>
        <GearComp size={340} color={P.sage} opacity={0.22} />
      </div>
      {/* smaller ghost */}
      <div style={{ position:'absolute', bottom:'22%', right:'-5%', pointerEvents:'none', transform:'rotate(-15deg)' }}>
        <GearComp size={180} color={P.sage} opacity={0.08} />
      </div>
      <div style={{ position:'absolute', inset:0, display:'flex', flexDirection:'column',
        justifyContent:'flex-end', padding:'60px 48px', zIndex:2 }}>
        {eyebrow && <IGLabel style={{ marginBottom:14 }}>{eyebrow}</IGLabel>}
        <div className="serif" style={{ fontSize:36, lineHeight:1.15, color:P.ink,
          letterSpacing:'-0.01em' }}>{title}</div>
        {sub && <div className="serif" style={{ fontStyle:'italic', fontSize:18, color:P.stone,
          marginTop:14, lineHeight:1.45 }}>{sub}</div>}
      </div>
    </IGFrame>
  );
}

// Gear comparison — two pieces of equipment side by side
function TplGearCompare({ w=640, h=640, eyebrow, leftGear='v60', leftLabel, rightGear='chemex', rightLabel }){
  const P = useP();
  const GEAR_MAP = { v60:GearV60, chemex:GearChemex, aeropress:GearAeropress, kettle:GearKettle, grinder:GearGrinder, scale:GearScale };
  const Left = GEAR_MAP[leftGear] || GearV60;
  const Right = GEAR_MAP[rightGear] || GearChemex;
  return (
    <IGFrame w={w} h={h}>
      <div style={{ position:'absolute', inset:0, display:'flex' }}>
        <div style={{ flex:1, display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center', gap:16 }}>
          <Left size={200} color={P.sage} opacity={0.3} />
          <span className="sans" style={{ fontSize:14, fontWeight:700, color:P.ink }}>{leftLabel||leftGear}</span>
        </div>
        <div style={{ width:1, height:'60%', background:P.line, alignSelf:'center' }} />
        <div style={{ flex:1, display:'flex', flexDirection:'column', alignItems:'center', justifyContent:'center', gap:16 }}>
          <Right size={200} color={P.sage} opacity={0.3} />
          <span className="sans" style={{ fontSize:14, fontWeight:700, color:P.ink }}>{rightLabel||rightGear}</span>
        </div>
      </div>
      {eyebrow && <div style={{ position:'absolute', top:40, left:0, right:0, textAlign:'center', zIndex:2 }}>
        <IGLabel>{eyebrow}</IGLabel>
      </div>}
    </IGFrame>
  );
}

// Story with landscape
function TplStoryOrigin({ country, terrain='andes', subtitle }){
  const P = useP();
  return (
    <IGFrame w={446} h={792} light>
      <IGLandscape terrain={terrain} placement="full" opacity={0.9} />
      <div style={{ position:'absolute', inset:0, zIndex:2,
        background:'linear-gradient(to top, #211B16ee 0%, #211B16aa 30%, transparent 60%)' }} />
      <div style={{ position:'absolute', bottom:80, left:0, right:0, textAlign:'center', zIndex:3, padding:'0 32px' }}>
        <IGLabel color="#E26F38" style={{ marginBottom:12 }}>Origin spotlight</IGLabel>
        <div className="serif" style={{ fontSize:38, color:'#F4ECDD', lineHeight:1.1 }}>{country}</div>
        {subtitle && <div className="serif" style={{ fontStyle:'italic', fontSize:16, color:'#D6C9B4',
          marginTop:10, lineHeight:1.4 }}>{subtitle}</div>}
      </div>
    </IGFrame>
  );
}

// Carousel cover with gear illustration
function TplCarouselGearCover({ w=640, h=800, gear='v60', title, sub, pages=5 }){
  const P = useP();
  const GEAR_MAP = { v60:GearV60, chemex:GearChemex, aeropress:GearAeropress, kettle:GearKettle, grinder:GearGrinder, scale:GearScale };
  const GearComp = GEAR_MAP[gear] || GearV60;
  return (
    <IGFrame w={w} h={h}>
      <div style={{ position:'absolute', top:'8%', left:'50%', transform:'translateX(-50%)', pointerEvents:'none' }}>
        <GearComp size={360} color={P.sage} opacity={0.2} />
      </div>
      <div style={{ position:'absolute', inset:0, display:'flex', flexDirection:'column',
        justifyContent:'flex-end', padding:'56px 48px', zIndex:2 }}>
        <IGLabel style={{ marginBottom:14 }}>Brew guide</IGLabel>
        <div className="serif" style={{ fontSize:42, lineHeight:1.1, color:P.ink,
          letterSpacing:'-0.02em' }}>{title}</div>
        {sub && <div className="serif" style={{ fontStyle:'italic', fontSize:18, color:P.stone,
          marginTop:12, lineHeight:1.4 }}>{sub}</div>}
        <div style={{ display:'flex', alignItems:'center', gap:8, marginTop:24 }}>
          <span className="sans" style={{ fontSize:11, fontWeight:600, letterSpacing:'0.12em',
            textTransform:'uppercase', color:P.stoneLt }}>Swipe</span>
          <svg width="20" height="12" viewBox="0 0 20 12" fill="none" stroke={P.stoneLt}
            strokeWidth="1.5" strokeLinecap="round"><path d="M1 6h16M13 1l5 5-5 5" /></svg>
        </div>
      </div>
      <div style={{ position:'absolute', top:40, right:48, display:'flex', gap:5, zIndex:2 }}>
        {Array.from({length:pages}).map((_,k)=>(
          <div key={k} style={{ width:k===0?16:6, height:6, borderRadius:3,
            background:k===0?P.sage:P.line }} />
        ))}
      </div>
    </IGFrame>
  );
}


Object.assign(window, {
  IGLandscape, IG_TERRAIN_FULL, IG_ARCH_SIG,
  BeanCherry, BeanRoasted, BeanCrossSection, BeanScatter,
  GearV60, GearChemex, GearAeropress, GearKettle, GearGrinder, GearScale,
  TplOriginLandscape, TplBeanCard, TplGearCard, TplGearCompare,
  TplStoryOrigin, TplCarouselGearCover,
});
