// Shared shadow DOM styles. A shop theme restyles the widgets through these custom properties,
// set on the element or any ancestor (they inherit through the shadow root):
//   --lf-font, --lf-font-size, --lf-text, --lf-muted, --lf-background, --lf-surface, --lf-border,
//   --lf-accent, --lf-accent-text, --lf-focus, --lf-warning, --lf-warning-background, --lf-radius, --lf-gap
// Every default meets WCAG AA contrast on the default background.

// The base text size is at least 16 px: Dawn and the themes built on it set the root to 62.5%,
// so 1rem is 10 px there. 16 px also stops iOS Safari zooming in when a shopper taps a box. A
// theme or shopper with a larger root size still gets it, and --lf-font-size overrides as before.
// A summary is a flex box, which hides the browser's own fold arrow, so summary::before draws one:
// it points right while the section is folded and down once it is open.
export const baseStyles = `
:host {
  display: block;
  font-family: var(--lf-font, inherit);
  font-size: var(--lf-font-size, max(1rem, 16px));
  line-height: 1.5;
  color: var(--lf-text, #1c1c1c);
  container-type: inline-size;
  min-width: 0;
}
:host([hidden]) { display: none; }
* { box-sizing: border-box; }
.lf {
  background: var(--lf-background, #ffffff);
  border: 1px solid var(--lf-border, #8a8a8a);
  border-radius: var(--lf-radius, 8px);
  padding: var(--lf-gap, 16px);
  display: grid;
  gap: var(--lf-gap, 16px);
  min-width: 0;
  overflow-wrap: anywhere;
}
h2, h3, h4 { margin: 0; line-height: 1.25; }
h2 { font-size: 1.25em; }
h3 { font-size: 1.1em; }
h4 { font-size: 1em; }
p, ul, ol, dl { margin: 0; }
ul, ol { padding-left: 1.25em; }
.muted { color: var(--lf-muted, #505050); }
.small { font-size: 0.9em; }
.stack { display: grid; gap: 8px; min-width: 0; }
.row { display: flex; flex-wrap: wrap; gap: 8px 16px; align-items: end; min-width: 0; }
button, .button {
  font: inherit;
  min-height: 44px;
  min-width: 44px;
  padding: 8px 16px;
  border-radius: var(--lf-radius, 8px);
  border: 2px solid var(--lf-accent, #1f5f8b);
  background: var(--lf-accent, #1f5f8b);
  color: var(--lf-accent-text, #ffffff);
  cursor: pointer;
}
button.secondary {
  background: transparent;
  color: var(--lf-accent, #1f5f8b);
}
button:disabled { opacity: 0.55; cursor: not-allowed; }
label { display: grid; gap: 4px; font-weight: 600; min-width: 0; }
label.check { display: flex; gap: 12px; align-items: flex-start; font-weight: 400; }
input[type="number"], input[type="text"], select {
  font: inherit;
  min-height: 44px;
  width: 100%;
  max-width: 12em;
  padding: 8px 10px;
  border: 1px solid var(--lf-border, #8a8a8a);
  border-radius: var(--lf-radius, 8px);
  background: var(--lf-background, #ffffff);
  color: inherit;
}
input[type="checkbox"] { width: 24px; height: 24px; margin: 10px; flex: none; accent-color: var(--lf-accent, #1f5f8b); }
:focus-visible { outline: 3px solid var(--lf-focus, #1f5f8b); outline-offset: 2px; }
.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.panel {
  background: var(--lf-surface, #f4f4f4);
  border-radius: var(--lf-radius, 8px);
  padding: 12px;
  min-width: 0;
}
.warning {
  background: var(--lf-warning-background, #fff4d6);
  color: var(--lf-warning, #5c3b00);
  border-left: 4px solid currentColor;
  padding: 8px 12px;
  border-radius: 4px;
}
.answer { font-size: 1.1em; font-weight: 700; }
.result { display: grid; gap: var(--lf-gap, 16px); min-width: 0; }
.result > * { min-width: 0; }
@container (min-width: 620px) {
  .result { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); align-items: start; }
  .result.single { grid-template-columns: minmax(0, 1fr); }
}
figure { margin: 0; display: grid; gap: 4px; }
canvas, svg { display: block; max-width: 100%; height: auto; background: var(--lf-surface, #f4f4f4); border: 1px solid var(--lf-border, #8a8a8a); }
dl { display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; }
dt { color: var(--lf-muted, #505050); }
dd { margin: 0; font-weight: 600; }
table { border-collapse: collapse; width: 100%; font-size: 0.9em; }
th, td { text-align: left; padding: 4px 6px; border-bottom: 1px solid var(--lf-border, #8a8a8a); }
.table-wrap { overflow-x: auto; max-width: 100%; }
details > summary { cursor: pointer; min-height: 44px; display: flex; align-items: center; font-weight: 600; }
details > summary::-webkit-details-marker { display: none; }
details > summary::before { content: ""; flex: none; width: 0.45em; height: 0.45em; margin: 0 0.75em 0 0.2em; border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: rotate(-45deg); }
details[open] > summary::before { transform: rotate(45deg); }
[hidden] { display: none !important; }
.plain-list { list-style: none; padding: 0; }
`;

// The quantities planner's share of baseStyles: the same rules in the same order with the same values,
// without those only the gang sheet builder uses (h3, h4, ol, lists of terms, panels, tables, selects, text
// boxes, canvases), one rule a line so the planner's file stays small. The rules only a result needs come
// with the result view (src/quantities-view.ts, resultStyles). test/styles.test.ts checks that each rule
// here and there is a rule of baseStyles.
export const quantitiesStyles = `:host{display:block;font-family:var(--lf-font,inherit);font-size:var(--lf-font-size,max(1rem,16px));line-height:1.5;color:var(--lf-text,#1c1c1c);container-type:inline-size;min-width:0}
:host([hidden]){display:none}
*{box-sizing:border-box}
.lf{background:var(--lf-background,#ffffff);border:1px solid var(--lf-border,#8a8a8a);border-radius:var(--lf-radius,8px);padding:var(--lf-gap,16px);display:grid;gap:var(--lf-gap,16px);min-width:0;overflow-wrap:anywhere}
h2{margin:0;line-height:1.25}
h2{font-size:1.25em}
p{margin:0}
.muted{color:var(--lf-muted,#505050)}
.stack{display:grid;gap:8px;min-width:0}
.row{display:flex;flex-wrap:wrap;gap:8px 16px;align-items:end;min-width:0}
button{font:inherit;min-height:44px;min-width:44px;padding:8px 16px;border-radius:var(--lf-radius,8px);border:2px solid var(--lf-accent,#1f5f8b);background:var(--lf-accent,#1f5f8b);color:var(--lf-accent-text,#ffffff);cursor:pointer}
button.secondary{background:transparent;color:var(--lf-accent,#1f5f8b)}
button:disabled{opacity:0.55;cursor:not-allowed}
label{display:grid;gap:4px;font-weight:600;min-width:0}
label.check{display:flex;gap:12px;align-items:flex-start;font-weight:400}
input[type="number"]{font:inherit;min-height:44px;width:100%;max-width:12em;padding:8px 10px;border:1px solid var(--lf-border,#8a8a8a);border-radius:var(--lf-radius,8px);background:var(--lf-background,#ffffff);color:inherit}
input[type="checkbox"]{width:24px;height:24px;margin:10px;flex:none;accent-color:var(--lf-accent,#1f5f8b)}
:focus-visible{outline:3px solid var(--lf-focus,#1f5f8b);outline-offset:2px}
.warning{background:var(--lf-warning-background,#fff4d6);color:var(--lf-warning,#5c3b00);border-left:4px solid currentColor;padding:8px 12px;border-radius:4px}
[hidden]{display:none !important}`;

// Adds the styles to a shadow root. Constructed stylesheets work under a strict Content-Security-Policy
// with no 'unsafe-inline'; older browsers fall back to a <style> element.
export function applyStyles(root: ShadowRoot, css: string) {
  try {
    const sheet = new CSSStyleSheet();
    sheet.replaceSync(css);
    root.adoptedStyleSheets = [sheet];
  } catch {
    root.append(el("style", css));
  }
}

// Builds a detached element from an HTML string. Only ever called with static markup; user text is set
// through textContent, never through innerHTML.
export function template(html: string): DocumentFragment {
  const t = document.createElement("template");
  t.innerHTML = html;
  return t.content;
}

export function el<K extends keyof HTMLElementTagNameMap>(tag: K, text?: string, className?: string): HTMLElementTagNameMap[K] {
  const node = document.createElement(tag);
  if (text !== undefined) node.textContent = text;
  if (className) node.className = className;
  return node;
}
