/* Kitbit: one stylesheet for every page.
   One accent (price-sticker yellow), ink for text and lines, system fonts, no images.
   Yellow marks "the answer": the header, the hub hero, the glyph tiles, the result panel.

   Classes the tool pages reuse:
     .wrap    centred column, max 60rem with 1rem gutters
     .tool    the panel that holds the inputs: .field blocks, then one .result
     .field   one labelled input: <div class="field"><label for="x">..</label><input id="x" ..><p class="hint">..</p></div>
              (text, number and search inputs, select and textarea are styled; checkbox, range, file keep native looks)
     .hint    small helper text under a field or inside a result
     .result  yellow answer panel: an h2/h3 label, then a direct-child <strong> or <output> for the big number
              (a <strong> inside a <p> or <dd> stays normal text), or a <dl> of rows. In that <dl> every <dt> is
              followed by exactly one <dd>, all direct children (no wrapper divs): it is a two-column grid,
              label on the left, value on the right. A <p class="hint" role="status"> inside is a live note: leave it
              in the page (never hidden) and change only its text, so it takes no room while empty.
     .faq     <section class="faq"><h2>..</h2><details><summary>Q</summary><p>A</p></details> ..</section>
     .promo   app promo card, one app per card (glyph tile, heading, text, Play button), lives in the footer of every page (the hub
              footer stacks two); on a tool page a contextual <aside class="promo" aria-labelledby=".."> may follow the tool, and a
              .promo inside <main> gets room above and below
     .btn     button look for an <a>; bare <button> elements get it too. Add btn-secondary for the outline look
              (on a bare <button> btn-secondary alone is enough). button:disabled and .btn[aria-disabled="true"]
              look disabled; an aria-disabled link still takes clicks, so block them in JS.
     .sr-only visually hidden text for screen readers
   Only on one tool page, or for prose:
     .modes   (harga jual, watermark) radio buttons drawn as a row of tabs: <fieldset class="modes"><legend>..</legend>
              <label><input type="radio" name=".." value=".."><span>Tab text</span></label> ..; hints after it get room below
     .group   (HPP) a <fieldset> of cost rows, legend as the group title; .row is one row: .field.name, .field.amount, a button
     .formula a formula set apart in the prose, one line in a <p class="formula">
     .tool--wide, .wm, .wm-file, .wm-preview, .wm-controls, .wm-range, .wm-value
              (watermark) the wide .tool and its layout: .wm holds .wm-file (the file field), .wm-preview (drop zone
              with a <canvas> and the file error; JS adds is-over to it and has-photo to <html>) and .wm-controls
              (the settings); .wm-range is a slider with its value, .wm-value the value text
     .dh, .dh-form, .dh-preview, .items, .item, .item-actions, .item-grid, .item-name, .dh-pages
              (daftar harga) the wide .tool holds .dh: .dh-form (shop fields, the .items list, colour and size) and .dh-preview
              (the images). Each .item is an <li> holding a <fieldset>: its legend, .item-actions (move and remove buttons,
              pinned to the legend's line), then .item-grid with .item-name and the two price fields. .dh-pages lists the
              images, one <li> each with a full-size <canvas> shown scaled down and its download button */

:root {
  --accent: #ffc933;
  --accent-soft: #fff1c2;
  --ink: #1b2340;
  --ink-soft: #4b5471;
  --line: #6b7391;
  --paper: #fff;
  --ink-hover: #2b3560;
  --on-ink-soft: #dde1ee;
  --disabled-bg: #e6e8f0;
  --disabled-ink: #5f6786;
  --font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --r-s: 8px;
  --r-m: 16px;
  color-scheme: light;
  accent-color: var(--ink);
}

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100dvh;
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 1.0625rem/1.6 var(--font);
}
main { flex: 1; }
img, canvas { max-width: 100%; height: auto; }

h1, h2, h3 { line-height: 1.15; letter-spacing: -0.02em; text-wrap: balance; }
h1 { margin: 1.75rem 0 0.75rem; font-size: clamp(1.875rem, 8vw, 2.75rem); font-weight: 800; }
h2 { margin: 2rem 0 0.75rem; font-size: 1.5rem; font-weight: 800; }
h3 { margin: 1.5rem 0 0.5rem; font-size: 1.125rem; font-weight: 700; }
p, ul, ol, dl { margin: 0 0 1rem; }
p { max-width: 38rem; }
a { color: inherit; text-decoration-thickness: 2px; text-underline-offset: 0.2em; }
:focus-visible { outline: 3px solid var(--ink); outline-offset: 3px; }

.wrap { width: min(100% - 2rem, 60rem); margin-inline: auto; }
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}
.skip {
  position: absolute;
  top: -4rem;
  left: 0.5rem;
  z-index: 10;
  padding: 0.75rem 1rem;
  background: var(--ink);
  color: var(--paper);
  border-radius: var(--r-s);
}
.skip:focus { top: 0.5rem; }

/* Header: brand and tool nav on yellow */
.site-header { background: var(--accent); }
.site-header .wrap { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; padding-top: 0.25rem; }
.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
  min-height: 3rem;
  font-size: 1.375rem;
  font-weight: 800;
  letter-spacing: -0.02em;
  text-decoration: none;
}
.brand img { display: block; }
.tools-nav { flex: none; width: calc(100% + 2rem); margin-inline: -1rem; }
.tools-nav ul { display: flex; margin: 0; padding: 0 0.25rem; list-style: none; overflow-x: auto; }
.tools-nav a {
  display: flex;
  align-items: center;
  min-height: 2.75rem;
  padding: 0 0.75rem;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}
.tools-nav a:hover { text-decoration: underline; }
.tools-nav a[aria-current="page"] { font-weight: 800; box-shadow: inset 0 -4px 0 var(--ink); }
.tools-nav :focus-visible { outline-offset: -3px; }

/* Hub hero: the poster headline on yellow, continuing the header */
.hero { padding: 1rem 0 2.5rem; background: var(--accent); }
.hero h1 { margin: 0 0 1rem; font-size: clamp(2.5rem, 12vw, 4.5rem); line-height: 1.02; letter-spacing: -0.035em; }
.hero p { margin: 0; font-size: 1.1875rem; line-height: 1.5; }

/* Hub tool tiles */
.cards { display: grid; gap: 1rem; margin: 2rem 0 0; padding: 0; list-style: none; }
.card {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  padding: 1.125rem;
  background: var(--paper);
  border: 2px solid var(--ink);
  border-radius: var(--r-m);
}
.card:hover, .card:active { background: var(--accent-soft); }
.card h2, .card h3 { margin: 0 0 0.25rem; font-size: 1.25rem; font-weight: 800; }
.card p { margin: 0; color: var(--ink-soft); }
.card a { text-decoration: none; }
.card a::after { content: ""; position: absolute; top: 0; right: 0; bottom: 0; left: 0; border-radius: var(--r-m); }
.card a:focus-visible { outline: none; }
.card a:focus-visible::after { outline: 3px solid var(--ink); outline-offset: 3px; }
.glyph {
  flex: none;
  display: grid;
  place-items: center;
  width: 3.5rem;
  height: 3.5rem;
  background: var(--accent);
  border: 2px solid var(--ink);
  border-radius: var(--r-s);
  font-size: 1.375rem;
  font-weight: 800;
  letter-spacing: -0.03em;
}

/* Buttons */
.btn, button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 3rem;
  padding: 0.5rem 1.25rem;
  background: var(--ink);
  border: 2px solid var(--ink);
  border-radius: var(--r-s);
  color: var(--paper);
  font: inherit;
  font-weight: 700;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
}
.btn:hover, button:hover { background: var(--ink-hover); border-color: var(--ink-hover); }
.btn-secondary { background: var(--paper); color: var(--ink); }
.btn-secondary:hover { background: var(--accent-soft); border-color: var(--ink); }
/* Disabled: flat grey with a dashed edge and no hover, so it cannot pass for a pale primary or secondary button. */
button:disabled,
button:disabled:hover,
.btn[aria-disabled="true"],
.btn[aria-disabled="true"]:hover {
  background: var(--disabled-bg);
  border: 2px dashed var(--line);
  color: var(--disabled-ink);
  cursor: not-allowed;
}

/* Footer: promo card, then the colophon */
.site-footer { margin-top: 3rem; padding-bottom: 2rem; }
.promo {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: start;
  gap: 1rem;
  padding: 1.25rem;
  background: var(--ink);
  border-radius: var(--r-m);
  color: var(--paper);
}
.promo h2 { margin: 0 0 0.25rem; font-size: 1.25rem; }
.promo p { margin: 0; color: var(--on-ink-soft); }
.promo .glyph { color: var(--ink); } /* the card's text is white; the yellow tile keeps the ink text it has on the tool cards (white on yellow is 1.5:1) */
.promo .btn { grid-column: 1 / -1; background: var(--accent); border-color: var(--accent); color: var(--ink); }
.promo .btn:hover { background: var(--paper); border-color: var(--paper); }
.promo :focus-visible { outline-color: var(--paper); }
main .promo { margin: 2rem 0; }
.promo + .promo { margin-top: 1rem; } /* the hub footer holds one card per app */
.foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.75rem 1.5rem; margin-top: 1.5rem; }
.foot p { display: flex; flex-wrap: wrap; align-items: center; gap: 0 0.5rem; margin: 0; color: var(--ink-soft); }
.foot strong { color: var(--ink); }
.foot a { display: inline-block; padding: 0.5rem 0; }

/* Tool pages */
.tool { max-width: 40rem; margin: 1.5rem 0; padding: 1.25rem; background: var(--paper); border: 2px solid var(--ink); border-radius: var(--r-m); }
.tool > :first-child { margin-top: 0; }
.field { margin: 0 0 1.25rem; }
.field label { display: block; margin-bottom: 0.375rem; font-weight: 700; }
.field input:not([type]),
.field input[type="text"],
.field input[type="number"],
.field input[type="search"],
.field select,
.field textarea {
  display: block;
  width: 100%;
  min-height: 3rem;
  padding: 0.5rem 0.75rem;
  background: var(--paper);
  border: 2px solid var(--line);
  border-radius: var(--r-s);
  color: var(--ink);
  font: inherit;
}
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--ink); }
.field input[aria-invalid="true"] { border-color: var(--ink); }
.hint { margin: 0.375rem 0 0; font-size: 0.9375rem; color: var(--ink-soft); }
h1 + .hint { margin: -0.25rem 0 1.25rem; }

.result { margin: 1.25rem 0 0; padding: 1rem 1.25rem; background: var(--accent); border: 2px solid var(--ink); border-radius: var(--r-s); }
.result > :last-child { margin-bottom: 0; }
.result h2, .result h3 { margin: 0 0 0.25rem; font-size: 1rem; font-weight: 700; letter-spacing: 0; }
.result p { margin: 0 0 0.5rem; }
.result > strong, .result > output {
  display: block;
  font-size: clamp(1.75rem, 9vw, 2.5rem);
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -0.02em;
  margin: 0 0 0.5rem;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.result dl { display: grid; grid-template-columns: 1fr auto; gap: 0.5rem 1rem; margin: 0; }
.result dt { font-weight: 600; }
.result dd { margin: 0; font-weight: 800; text-align: right; font-variant-numeric: tabular-nums; }
.result .hint { color: var(--ink); }
.result .hint:empty { margin: 0; } /* a live note (role="status") stays in the page, empty until it has something to say */

/* Harga jual: the modes as a row of tabs. The radio is invisible but covers its tab, so it stays focusable and clickable. */
.modes { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.5rem; min-width: 0; margin: 0; padding: 0; border: 0; }
.modes legend { margin-bottom: 0.375rem; padding: 0; font-weight: 700; }
.modes label { position: relative; display: block; }
.modes input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.modes span {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 3rem;
  padding: 0.25rem 0.5rem;
  border: 2px solid var(--ink);
  border-radius: var(--r-s);
  font-weight: 700;
  line-height: 1.2;
  text-align: center;
}
.modes input:checked + span { background: var(--ink); color: var(--paper); }
/* Forced colours (Windows high contrast) drop the fill, so say "selected" with the system highlight. */
@media (forced-colors: active) { .modes input:checked + span { forced-color-adjust: none; background: Highlight; color: HighlightText; } }
.modes input:not(:checked):hover + span { background: var(--accent-soft); }
.modes input:focus-visible + span { outline: 3px solid var(--ink); outline-offset: 3px; }
.modes ~ .hint { margin: 0.5rem 0 1.25rem; }

/* HPP: cost rows in groups. On a phone the name takes a line, then the amount and the remove button share the next. */
.group { min-width: 0; margin: 0 0 1.5rem; padding: 0; border: 0; }
.group legend { margin-bottom: 0.5rem; padding: 0; font-size: 1.125rem; font-weight: 800; }
.row { display: grid; grid-template-columns: 1fr auto; align-items: start; gap: 0.5rem; margin-bottom: 0.75rem; }
.row .field { margin: 0; }
.row .name { grid-column: 1 / -1; }

.formula { padding: 0.75rem 1rem; background: var(--accent-soft); border-left: 4px solid var(--ink); border-radius: var(--r-s); font-weight: 700; }

/* Watermark: file picker, preview, settings. On a phone they stack. Once a photo is open (watermark.js puts has-photo on <html>)
   the preview stays pinned at the top while you scroll the settings, and the page's scroll padding is that pinned box plus some
   room, so a control that takes keyboard focus is scrolled clear of the box instead of being left underneath it (WCAG 2.4.11).
   From 52rem (see the end of this file) the preview sits beside the settings and needs neither.
   The preview box is also the drop zone, and it shows the error for a file that is not a photo. */
.tool--wide { max-width: none; }
.wm { display: grid; gap: 1.25rem; }
.wm > * { min-width: 0; }
.wm-file { margin: 0; }
.wm-preview {
  display: grid;
  place-items: center;
  min-height: 9rem;
  padding: 0.5rem;
  background: var(--accent-soft);
  border: 2px dashed var(--line);
  border-radius: var(--r-s);
  color: var(--ink-soft);
  text-align: center;
}
.wm-preview > * { pointer-events: none; } /* so a drag over the canvas or the text does not count as leaving the box */
.wm-preview p { margin: 0; padding: 0 0.5rem; }
.wm-preview .hint { margin-top: 0.5rem; color: var(--ink); font-weight: 700; } /* the file error, under the photo or the placeholder */
.wm-preview canvas { display: block; width: auto; max-height: 36vh; }
.wm-preview.is-over { background: var(--accent); border-color: var(--ink); }
.has-photo .wm-preview {
  position: sticky;
  top: 0;
  z-index: 1; /* above the positioned radio tabs that scroll underneath */
  border-style: solid;
  border-color: var(--ink);
  box-shadow: 0 0.5rem 0 var(--paper); /* a white band under the pinned box, so the settings do not touch its edge */
}
html.has-photo { scroll-padding-top: calc(var(--wm-pinned, 0px) + 2rem); } /* --wm-pinned: the box's height, kept current by watermark.js */
.wm-range { display: flex; align-items: center; gap: 0.75rem; }
.wm-range input { flex: 1; min-width: 0; min-height: 2.75rem; margin: 0; }
.wm-value { min-width: 3.25rem; font-weight: 700; text-align: right; font-variant-numeric: tabular-nums; }
.field input[type="color"] {
  display: block;
  width: 4.5rem;
  height: 3rem;
  padding: 0.25rem;
  background: var(--paper);
  border: 2px solid var(--line);
  border-radius: var(--r-s);
  cursor: pointer;
}
.wm-controls .modes { margin-bottom: 1.25rem; } /* the tabs sit bare, not in a .field, so they bring their own spacing */
.wm-controls button { width: 100%; }
.wm-controls > .hint { margin: 0.375rem 0 0; } /* the hints under the download button are not tab hints: undo the `.modes ~ .hint` spacing */

/* Daftar harga: on a phone the form comes first and the images after it. From 52rem (see the end of this file) the images
   sit beside the form and stay in view while a long list scrolls past. */
.dh { display: grid; gap: 1.5rem; }
.dh > * { min-width: 0; }
.dh h2 { margin: 1.75rem 0 0.75rem; font-size: 1.25rem; }
.dh-form > h2:first-child, .dh-preview > h2 { margin-top: 0; }
.dh .modes { grid-template-columns: 1fr 1fr; }
.items { margin: 0 0 1rem; padding: 0; list-style: none; }
.item { position: relative; padding: 0.75rem 0 1rem; border-top: 2px solid var(--line); }
.item fieldset { min-width: 0; margin: 0; padding: 0; border: 0; }
.item legend { padding: 0; font-weight: 800; line-height: 3rem; } /* as tall as the buttons beside it */
.item-actions { position: absolute; top: 0.75rem; right: 0; display: flex; gap: 0.5rem; }
.item-actions button { min-width: 3rem; padding-inline: 0.75rem; }
.item-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0.75rem; margin-top: 0.5rem; }
.item-grid .field { margin: 0; }
.item-name { grid-column: 1 / -1; }
.dh-pages { display: grid; gap: 1.5rem; margin: 1rem 0; padding: 0; list-style: none; }
.dh-pages li { display: grid; justify-items: center; gap: 0.75rem; }
.dh-pages canvas { display: block; width: auto; max-height: 75vh; border: 2px solid var(--ink); border-radius: var(--r-s); }
.dh-pages button { width: 100%; }

.faq { max-width: 40rem; margin: 2rem 0; }
.faq details { border-top: 2px solid var(--ink); }
.faq details:last-child { border-bottom: 2px solid var(--ink); }
.faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: 3rem;
  padding: 0.5rem 0;
  font-weight: 700;
  list-style: none;
  cursor: pointer;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; content: "+" / ""; flex: none; font-size: 1.5rem; line-height: 1; }
.faq details[open] summary::after { content: "\2212"; content: "\2212" / ""; }
.faq details > :not(summary) { margin: 0 0 1rem; }

@media (min-width: 40rem) {
  .site-header .wrap { flex-wrap: nowrap; }
  .tools-nav { width: auto; margin: 0 -0.75rem 0 0; }
  .tools-nav ul { padding: 0; overflow: visible; }
  .hero { padding: 2rem 0 3.5rem; }
  .hero p { font-size: 1.3125rem; max-width: 36rem; }
  .cards { grid-template-columns: 1fr 1fr; }
  .row { grid-template-columns: 1fr 12rem auto; }
  .row .name { grid-column: auto; }
  .promo { grid-template-columns: auto 1fr auto; align-items: center; }
  .promo .btn { grid-column: auto; }
}

/* Watermark on a wide screen: file picker and preview on the left, settings on the right. */
@media (min-width: 52rem) {
  .wm { grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); grid-template-rows: auto 1fr; column-gap: 1.5rem; align-items: start; }
  .wm-file { grid-area: 1 / 1; }
  .wm-preview { grid-area: 2 / 1; }
  .has-photo .wm-preview { top: 1rem; }
  html.has-photo { scroll-padding-top: 0; } /* the pinned preview no longer sits above the settings */
  .wm-preview canvas { max-height: 70vh; }
  .wm-controls { grid-area: 1 / 2 / 3 / 3; }

  /* Daftar harga: the images scroll on their own when they are taller than the window. The padding keeps the focus ring
     of a download button inside that scrolling box, the negative margin keeps the column lined up with the form. */
  .dh { grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr); column-gap: 2rem; align-items: start; }
  .dh-preview { position: sticky; top: 1rem; max-height: calc(100vh - 2rem); margin: -0.5rem; padding: 0.5rem; overflow-y: auto; }
  .dh-pages canvas { max-height: 65vh; }
}
