// Mella — shared design kit
// The product's design system, extracted by use. Both the public queue and the
// client portal (and later the dashboard) import these so they stay cohesive.
// Exposed on window for cross-file <script type="text/babel"> sharing.

/* ----------------------------------------------------------------- color */
function hexToRgba(hex, a) {
  const h = hex.replace('#', '');
  const f = h.length === 3 ? h.split('').map(x => x + x).join('') : h;
  const n = parseInt(f, 16);
  return `rgba(${(n >> 16) & 255}, ${(n >> 8) & 255}, ${n & 255}, ${a})`;
}
function lighten(hex, amt) {
  const h = hex.replace('#', '');
  const n = parseInt(h, 16);
  let r = (n >> 16) & 255, g = (n >> 8) & 255, b = n & 255;
  r = Math.round(r + (255 - r) * amt);
  g = Math.round(g + (255 - g) * amt);
  b = Math.round(b + (255 - b) * amt);
  return '#' + [r, g, b].map(x => x.toString(16).padStart(2, '0')).join('');
}

/* ------------------------------------------------------------- tokens */
// Constrained accent set — muted illustrator pigments, no free picker.
const ACCENTS = {
  teal:       '#2E5C5C',
  terracotta: '#C0613C',
  ochre:      '#B5863A',
  sienna:     '#A8503A',
  olive:      '#5E6B43',
  plum:       '#6E4757',
  ink:        '#33302B',
};
const TONES = {
  warm:  { bg:'#FAF7F2', surface:'#FFFFFF', sunk:'#F4F0E8', text:'#211C17', soft:'#48413A', faint:'#8C857E', rule:'#E9E2D7', chrome:'#EFEAE0', dark:false },
  paper: { bg:'#F5F4F0', surface:'#FFFFFF', sunk:'#EEEDE7', text:'#1B1B1A', soft:'#44433E', faint:'#8A887F', rule:'#E5E4DD', chrome:'#EAE9E3', dark:false },
  dusk:  { bg:'#191714', surface:'#221F1B', sunk:'#13110F', text:'#F1ECE4', soft:'#CFC7BC', faint:'#80776D', rule:'#332E28', chrome:'#141210', dark:true },
};
const FONTS = {
  editorial: { head:"'Instrument Serif', Georgia, serif", body:"'IBM Plex Sans', system-ui, sans-serif", hw:400, kern:'-0.015em', big:1 },
  classic:   { head:"'Newsreader', Georgia, serif",        body:"'IBM Plex Sans', system-ui, sans-serif", hw:500, kern:'-0.005em', big:0.84 },
  clean:     { head:"'IBM Plex Sans', system-ui, sans-serif", body:"'IBM Plex Sans', system-ui, sans-serif", hw:600, kern:'-0.02em', big:0.74 },
};
const MONO = "'IBM Plex Mono', ui-monospace, monospace";

// Shared pet palettes — the same "Maple" reads identically across surfaces.
// Each palette doubles as the loading/backdrop tone behind its real painting.
const PALS = {
  maple:   ['#E7CFA0', '#C49A63', '#7C5A32', '#33231400'],
  pepper:  ['#D7D2C7', '#9A9488', '#5F5A50', '#2C271F00'],
  otto:    ['#E2C79C', '#B98E57', '#6E4F2C', '#2f201200'],
  daisy:   ['#EAD9BA', '#C9A776', '#7E5E36', '#3a281700'],
  juniper: ['#D2D3C2', '#8A8D72', '#565843', '#2c2e2000'],
  banner:  ['#B4BC98', '#6E7853', '#3E4632', '#21251900'],
};

// Real artwork — public-domain Otto Eerelman dog paintings, web-optimized into
// ./art (1600px long edge). Each entry carries a focal point (`pos`) so a single
// original crops cleanly into any slot (wide banner, square avatar, tall card)
// via object-fit:cover. `pal` is the backdrop tone shown while it loads.
// `ratio` is width/height of the real file — let a gallery tile reserve the right
// height (aspect-ratio) so paintings show whole, undistorted, with no load jump.
const ART = {
  terrierUp:   { src:'art/terrier-up.jpg',            pos:'center 32%', pal:PALS.daisy,  ratio:0.777 },  // white terrier, begging
  litterBarn:  { src:'art/stbernard-litter-barn.jpg', pos:'center 40%', pal:PALS.otto,   ratio:1.447 },  // five St Bernard pups, barn
  leonberger:  { src:'art/leonberger-head.jpg',       pos:'center 24%', pal:PALS.otto,   ratio:0.776 },  // Leonberger head study
  affen:       { src:'art/affenpinscher.jpg',         pos:'center 34%', pal:PALS.juniper,ratio:0.709 },  // affenpinscher on chair
  twoPointers: { src:'art/two-pointers.jpg',          pos:'center 42%', pal:PALS.banner, ratio:1.528 },  // two pointers, landscape
  stbHead:     { src:'art/stbernard-head.jpg',        pos:'center 24%', pal:PALS.maple,  ratio:0.743 },  // St Bernard head study
  twoBorzois:  { src:'art/two-borzois.jpg',           pos:'center 40%', pal:PALS.daisy,  ratio:1.394 },  // two borzois on a terrace
  stbPup:      { src:'art/stbernard-pup.jpg',         pos:'center 28%', pal:PALS.otto,   ratio:0.674 },  // St Bernard puppy in straw
  litterDoor:  { src:'art/stbernard-litter-door.jpg', pos:'center 40%', pal:PALS.maple,  ratio:1.358 },  // six St Bernard pups, doorway
};

function resolveTheme(t) {
  const base = ACCENTS[t.accent] || ACCENTS.teal;
  const tone = TONES[t.tone] || TONES.warm;
  const f = FONTS[t.type] || FONTS.editorial;
  const accent = tone.dark ? lighten(base, 0.26) : base;
  return {
    a: accent,
    aSoft: hexToRgba(accent, tone.dark ? 0.20 : 0.12),
    aOn: '#FFFFFF',
    ...tone,
    muted: tone.dark ? '#9c9388' : '#79706E',
    f,
  };
}

/* ------------------------------------------------------------- painted art */
// Renders real artwork when given `src` (object-fit:cover + a focal `pos`), and
// falls back to the layered-gradient oil-portrait stand-in otherwise. Either way
// it honors the same radius/size `style` so every call site is interchangeable.
function Painting({ pal, src, pos, radius = 4, style }) {
  if (src) {
    const back = (pal && pal[2]) || '#C9A776';
    return (
      <div style={{ borderRadius: radius, overflow: 'hidden', position: 'relative', backgroundColor: back, ...style }}>
        <img src={src} alt="" loading="lazy" draggable={false} style={{
          width: '100%', height: '100%', objectFit: 'cover',
          objectPosition: pos || 'center', display: 'block', userSelect: 'none',
        }} />
      </div>
    );
  }
  const [c1, c2, c3, c4] = pal;
  return (
    <div style={{
      borderRadius: radius, position: 'relative', overflow: 'hidden', backgroundColor: c3,
      backgroundImage:
        `radial-gradient(ellipse at 30% 28%, ${c1} 0%, transparent 52%),` +
        `radial-gradient(ellipse at 72% 76%, ${c4} 0%, transparent 58%),` +
        `radial-gradient(ellipse at 52% 54%, ${hexToRgba(c2, 0.66)} 0%, transparent 70%),` +
        `linear-gradient(135deg, ${c2} 0%, ${c3} 100%)`,
      ...style,
    }}>
      <div style={{ position:'absolute', top:'24%', left:'30%', width:'16%', height:'12%',
        background:`radial-gradient(ellipse, ${hexToRgba(c1,0.6)} 0%, transparent 70%)`, borderRadius:'50%' }} />
      <div style={{ position:'absolute', bottom:'16%', right:'22%', width:'10%', height:'7%',
        background:`radial-gradient(ellipse, ${hexToRgba(c1,0.5)} 0%, transparent 70%)`, borderRadius:'50%' }} />
    </div>
  );
}

/* ------------------------------------------------------------- form bits */
const inpBase = (c) => ({
  width:'100%', fontFamily:"'IBM Plex Sans', system-ui, sans-serif", fontSize:16, color:c.text,
  background:c.surface, border:`1px solid ${c.rule}`, borderRadius:10, padding:'12px 13px', outline:'none',
});
const inp = (c) => inpBase(c);
const ta = (c) => ({ ...inpBase(c), resize:'none', lineHeight:1.5 });
function Field({ c, label, children, flex }) {
  return (
    <label style={{ display:'block', marginBottom:14, flex: flex ? 1 : undefined }}>
      <span style={{ fontFamily:MONO, fontSize:9.5, letterSpacing:'0.1em', textTransform:'uppercase', color:c.faint, display:'block', marginBottom:6 }}>{label}</span>
      {children}
    </label>
  );
}

/* ------------------------------------------------------------- bottom sheet */
// Adaptive: a bottom sheet on phone (native mobile convention), a centered modal
// on tablet/desktop (where a full-width bottom drawer looks wrong).
function BottomSheet({ c, onClose, children, maxHeight = '86%' }) {
  const screen = typeof document !== 'undefined' ? document.getElementById('mq-screen') : null;
  const frame = screen && screen.parentElement;        // the phone-shell frame (fixed height, overflow hidden)
  const positioned = !!frame;                          // anchor to phone if available, else viewport
  const pos = positioned ? 'absolute' : 'fixed';
  const wide = (typeof window !== 'undefined' ? window.innerWidth : 400) >= 700;
  const panel = wide
    ? { // centered modal
        position:pos, top:'50%', left:'50%', transform:'translate(-50%, -50%)', zIndex:2001,
        width:'min(460px, 92%)', maxHeight:'88%', borderRadius:18,
        padding:'22px 22px calc(20px + env(safe-area-inset-bottom))',
        boxShadow:'0 40px 90px -30px rgba(0,0,0,0.5)',
      }
    : { // bottom sheet
        position:pos, bottom:0, left:0, right:0, margin:'0 auto', zIndex:2001,
        width: positioned ? '100%' : 'min(392px, 94vw)', borderRadius:'22px 22px 0 0',
        padding:'10px 20px calc(20px + env(safe-area-inset-bottom))',
        boxShadow:'0 -20px 60px -20px rgba(0,0,0,0.4)', borderTop:`1px solid ${c.rule}`,
      };
  const overlay = (
    <React.Fragment>
      <div onClick={onClose} style={{
        position:pos, inset:0, zIndex:2000,
        background: hexToRgba('#000', 0.42), animation:'mq-fade .2s ease',
      }} />
      <div style={{ background:c.bg, color:c.text, fontFamily:c.f.body, overflowY:'auto', maxHeight, ...panel }}>
        {!wide && <div style={{ width:38, height:4, borderRadius:99, background:c.rule, margin:'0 auto 16px' }} />}
        {children}
      </div>
    </React.Fragment>
  );
  return (frame && window.ReactDOM && ReactDOM.createPortal)
    ? ReactDOM.createPortal(overlay, frame) : overlay;
}

/* ------------------------------------------------------------- viewport */
// Reports the live viewport width + a tier so layouts can reflow.
// tiers: 'phone' (<700) · 'tablet' (700–1024) · 'desktop' (>1024)
function useViewport() {
  const get = () => (typeof window !== 'undefined' ? window.innerWidth : 1200);
  const [w, setW] = React.useState(get());
  React.useEffect(() => {
    const on = () => setW(get());
    window.addEventListener('resize', on);
    return () => window.removeEventListener('resize', on);
  }, []);
  return { w, tier: w < 700 ? 'phone' : (w <= 1024 ? 'tablet' : 'desktop'), wide: w >= 700 };
}

/* ------------------------------------------------------------- phone shell */
const _Bars = () => <svg width="17" height="11" viewBox="0 0 17 11"><g fill="currentColor">{[0,1,2,3].map(i=><rect key={i} x={i*4.5} y={8-i*2.4} width="3" height={3+i*2.4} rx="0.6"/>)}</g></svg>;
const _Wifi = () => <svg width="15" height="11" viewBox="0 0 15 11" fill="none"><path d="M7.5 9.5l0 0" stroke="currentColor" strokeWidth="2" strokeLinecap="round"/><path d="M2 5a8 8 0 0111 0M4.4 7.2a4.6 4.6 0 016.2 0" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"/></svg>;
const _Batt = () => <svg width="24" height="11" viewBox="0 0 24 11" fill="none"><rect x="0.5" y="0.5" width="20" height="10" rx="2.6" stroke="currentColor" opacity="0.4"/><rect x="2" y="2" width="15" height="7" rx="1.4" fill="currentColor"/><rect x="21.5" y="3.5" width="1.6" height="4" rx="0.8" fill="currentColor" opacity="0.4"/></svg>;

function PhoneShell({ t, url = 'mella.studio/iris', screenId = 'mq-screen', children }) {
  const c = resolveTheme(t);
  const { wide } = useViewport();
  const embed = typeof window !== 'undefined' && /[?&]embed=1/.test(window.location.search);
  // Real phones (and the embed showcase) fill the screen with no fake device bezel;
  // the real browser already provides the status bar and the address bar.
  if (embed || !wide) {
    return (
      <div id={screenId} style={{ height:'100vh', overflowY:'auto', WebkitOverflowScrolling:'touch', background:c.bg, position:'relative' }}>
        {children}
      </div>
    );
  }
  // Wider viewports: present a browser-style frame; content reflows to fill the width.
  return (
    <div style={{ minHeight:'100vh', display:'flex', alignItems:'flex-start', justifyContent:'center', padding:'28px 20px' }}>
      <div style={{ width:'min(1000px, 96vw)', height:'min(880px, 90vh)', background:c.bg, borderRadius:16,
        boxShadow:'0 50px 100px -30px rgba(40,32,24,0.5), 0 0 0 1px rgba(0,0,0,0.04)', overflow:'hidden',
        position:'relative', display:'flex', flexDirection:'column' }}>
        <div style={{ background:c.chrome, flexShrink:0, display:'flex', alignItems:'center', gap:8, padding:'0 16px', height:42, borderBottom:`1px solid ${c.rule}` }}>
          <div style={{ display:'flex', gap:7 }}>{[0,1,2].map(i=><span key={i} style={{ width:11, height:11, borderRadius:'50%', background:hexToRgba('#000',0.08) }} />)}</div>
          <div style={{ margin:'0 auto', background:c.bg, border:`1px solid ${c.rule}`, borderRadius:7, padding:'5px 16px', fontFamily:MONO, fontSize:11.5, color:c.soft, display:'flex', alignItems:'center', gap:7 }}>
            <span style={{ fontSize:9, color:c.faint }}>🔒</span> {url}
          </div>
        </div>
        <div id={screenId} style={{ flex:1, overflowY:'auto', WebkitOverflowScrolling:'touch', position:'relative' }}>
          {children}
        </div>
      </div>
    </div>
  );
}

/* ------------------------------------------------------------- keyframes */
(function injectKeyframes() {
  if (document.getElementById('mella-kit-kf')) return;
  const s = document.createElement('style');
  s.id = 'mella-kit-kf';
  s.textContent =
    '@keyframes mq-pulse{0%{transform:scale(1);opacity:.7}70%{transform:scale(2.1);opacity:0}100%{opacity:0}}' +
    '@keyframes mq-rise{from{transform:translateY(100%)}to{transform:translateY(0)}}' +
    '@keyframes mq-fade{from{opacity:0}to{opacity:1}}' +
    '@keyframes mq-confetti{to{transform:translateY(320px) rotate(360deg);opacity:0}}';
  document.head.appendChild(s);
})();

Object.assign(window, {
  hexToRgba, lighten, ACCENTS, TONES, FONTS, MONO, PALS, ART, useViewport,
  resolveTheme, Painting, inpBase, inp, ta, Field, BottomSheet, PhoneShell,
});
