/* ============================================================
   Convertburda — shared design tokens & components
   All colors live here as CSS variables (rule 2). No hex outside :root.
   ============================================================ */
:root {
  --bg: #eef1f5;
  --paper: #ffffff;
  /* header matches the logo's own background so the JPG blends in seamlessly */
  --header-bg: rgba(255, 255, 255, .92);
  --ink: #111820;
  --muted: #5b6673;
  --line: #dbe1e9;
  --accent: #d98a1f;
  --accent-ink: #5a3808;
  --accent2: #2f7dd9;
  --accent2-ink: #123a63;
  --accent3: #1f9e7c;
  --accent3-ink: #0f5c46;
  --grid-line: #e3e8ef;
  --ad-bg: #eff3f8;
  --ad-line: #c9d3df;
  --ok: #2f7d4f;
  --danger: #a3341f;
  --shadow-sm: rgba(17, 24, 32, .05);
  --shadow-lg: rgba(17, 24, 32, .28);
  /* the logo is a white-background JPG; it keeps its own white badge in dark mode */
  --logo-bg: #ffffff;
  --radius: 10px;
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
  --ui: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

/* Dark theme (Fikret's light/dark toggle, 2026-07-10) — same accents, inverted surfaces */
:root[data-theme="dark"] {
  --bg: #10141a;
  --paper: #1a212b;
  --header-bg: rgba(21, 27, 35, .92);
  --ink: #e7ecf3;
  --muted: #9aa6b5;
  --line: #2d3745;
  --accent: #e39b33;
  --accent-ink: #f0c896;
  --accent2: #4f97e8;
  --accent2-ink: #a8cdf5;
  --accent3: #4dcda8;
  --accent3-ink: #a8f0da;
  --grid-line: #202834;
  --ad-bg: #171d26;
  --ad-line: #313d4c;
  --ok: #58b183;
  --danger: #e06a52;
  --shadow-sm: rgba(0, 0, 0, .25);
  --shadow-lg: rgba(0, 0, 0, .55);
}

* { box-sizing: border-box; }
html, body { margin: 0; }
body {
  font-family: var(--ui);
  color: var(--ink);
  background:
    radial-gradient(1100px 520px at 15% -10%, color-mix(in srgb, var(--accent) 10%, transparent), transparent),
    radial-gradient(900px 460px at 100% 0%, color-mix(in srgb, var(--accent2) 8%, transparent), transparent),
    var(--bg);
  background-attachment: fixed;
  position: relative;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
/* grid overlay removed (Fikret 2026-07-10): clean color wash only */
a { color: var(--accent-ink); }
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

/* ---- header ---- */
header {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--header-bg);
  backdrop-filter: blur(6px);
  border-bottom: 1px solid var(--line);
}
header::before {
  content: "";
  display: block;
  height: 3px;
  background: linear-gradient(90deg, var(--accent), var(--accent2));
}
.bar { max-width: 1180px; margin: 0 auto; display: flex; align-items: center; gap: 18px; padding: 12px 18px; }
.logo { font-weight: 800; letter-spacing: -.02em; font-size: 19px; display: flex; align-items: center; gap: 9px; text-decoration: none; color: var(--ink); }
.logo img { height: 54px; width: auto; display: block; }
.logo .mark { width: 22px; height: 22px; border: 2px solid var(--ink); border-radius: 5px; position: relative; flex: none; }
.logo .mark::after { content: ""; position: absolute; inset: 4px 4px auto auto; width: 6px; height: 6px; background: var(--accent); border-radius: 1px; }
.spacer { flex: 1; }
.ghost { background: none; border: 1px solid var(--line); color: var(--ink); padding: 8px 13px; border-radius: 8px; font: inherit; font-size: 14px; cursor: pointer; text-decoration: none; display: inline-block; }
.ghost:hover { border-color: var(--muted); }
.ghost.active { border-color: var(--accent2); color: var(--accent2-ink); background: color-mix(in srgb, var(--accent2) 12%, transparent); }
.pro { border-color: var(--accent); color: var(--accent-ink); }
.pro-short { display: none; }

/* Phone/tablet header (2026-07-13 — Fikret's iPhone screenshot: the Pro button fell
   off the right edge). His chosen fix: shrink the ribbon logo ~45% on small screens
   and tighten the spacing; additionally the Pro button shows just "Pro" and the
   account button drops its text — both then match the header's existing icon-box
   pattern (flag/view/theme), with title/aria-label keeping them accessible. */
@media (max-width: 840px) {
  .bar { gap: 8px; padding: 10px 10px; }
  .logo img { height: 30px; }
  .bar .ghost { padding: 7px 9px; font-size: 13px; }
  .account-label, .pro-full { display: none; }
  .pro-short { display: inline; }
}
button:focus-visible, a:focus-visible, label:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---- layout (rule 1: fixed-ratio, never deforms on resize) ----
   Simplified 2026-07-20: the ad no longer lives inside .wrap as a grid column —
   it's ONE sticky slot (see .ad-rail below) positioned against the viewport, set
   once by _Layout.cshtml for every page. .wrap just centers its own content, same
   as it would if ads didn't exist at all. */
.wrap { max-width: 1180px; margin: 0 auto; padding: 22px 18px 60px; }
main { min-width: 0; }

/* ---- the one ad slot (Fikret 2026-07-20: "1 sticky one rechtsboven vertikaal") ----
   Softened box while AdSense approval is pending (a loud dashed box reads as
   unfinished, not ad-supported) — once real units go live, <ins class="adsbygoogle">
   replaces this box and this styling stops applying. Positioned with a viewport
   calc rather than a grid column: sits just right of .wrap's centered content
   (max-width 1180px), further out on a studio page (.wide, max-width 1400px).
   Sticky, so it stays in view while the page scrolls, per Fikret's own pasted
   ad-strategy source. Hidden below ~1400/1620px — tablets, most laptops and every
   phone never see it, matching Fikret's "don't let the widening show on small
   screens" goal; AdSense Auto Ads (Anchor/Vignette, dashboard-configured, not
   here) is the intended mobile monetization layer instead. */
.ad-rail {
  position: fixed; top: 90px; width: 160px;
  left: calc((100vw + 1180px) / 2 + 20px);
}
.ad-rail.wide { left: calc((100vw + 1400px) / 2 + 20px); }
@media (max-width: 1400px) { .ad-rail:not(.wide) { display: none; } }
@media (max-width: 1620px) { .ad-rail.wide { display: none; } }
.ad {
  background: var(--ad-bg); border: 1px solid color-mix(in srgb, var(--ad-line) 55%, transparent); border-radius: 8px;
  color: color-mix(in srgb, var(--muted) 40%, var(--ad-bg)); font-size: 10px; letter-spacing: .08em; text-transform: uppercase;
  display: flex; align-items: center; justify-content: center; text-align: center;
  min-height: 600px;
  /* hard boundary (Fikret 2026-07-17): whatever creative Google eventually loads,
     it can never spill over neighbouring tiles/text — the slot clips, full stop */
  overflow: hidden;
}
/* same guarantee once a real AdSense unit replaces the placeholder: the <ins> can
   never grow wider than its slot, and anything oversized inside it is clipped */
ins.adsbygoogle { display: block; max-width: 100%; overflow: hidden; }

/* ---- house ad (Fikret 2026-08-02) ----
   Fills the one slot with our own promo while AdSense is not yet approved, instead of
   an empty box carrying the literal word "advertisement". .ad sets uppercase 10px muted
   type for that placeholder, so everything it would inherit is reset here. Only the
   headline and the button carry text, both from keys that already exist in ten
   languages. See _AdRail.cshtml for what to do once a real ad unit goes in. */
.ad.house { align-items: stretch; padding: 16px 12px; text-transform: none; letter-spacing: 0; }
.house-in {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 11px; width: 100%; text-decoration: none; color: var(--ink);
}
.house-logo { width: 46px; height: 46px; object-fit: contain; }
/* de leuze spelt B-U-R-D-A: de beginletters dragen het merk, dus die krijgen het accent */
.house-slogan { font-size: 10.5px; line-height: 1.45; color: var(--muted); }
.house-slogan b { color: var(--accent-ink); font-weight: 800; }
.house-h { font-size: 13.5px; line-height: 1.3; font-weight: 700; color: var(--ink); }
.house-list { display: flex; flex-direction: column; gap: 6px; font-size: 11px; line-height: 1.25; color: var(--muted); }
/* the button reuses .btn so its gradient and its deliberately dark ink (white on our
   light orange does not carry) stay defined in exactly one place — only the size is
   tightened for a 160px-wide rail */
.house-cta { padding: 8px 12px; font-size: 12px; }
.house-in:hover .house-cta { filter: brightness(1.04); }
.house-in:hover .house-h { color: var(--accent-ink); }

/* ---- category page's full tool listing (2026-07-20, Fikret) ---- */
.tool-listing dt { margin-top: 16px; }
.tool-listing dt:first-child { margin-top: 0; }
.tool-listing dt a { font-weight: 700; font-size: 15px; color: var(--ink); text-decoration: none; }
.tool-listing dt a:hover { color: var(--accent-ink); text-decoration: underline; }
.tool-listing dd { margin: 2px 0 0; color: var(--muted); font-size: 13.5px; }

/* ---- preview watermark guard (2026-07-20, Fikret) ----
   A screen-recording/screenshot can't tell watermark pixels from "real" pixels — so this
   is a real, rendered DOM overlay, not something CSS could hide from a capture tool. The
   pattern (a tiled, rotated SVG background-image) is generated once in JS per container;
   see window.cbPreviewGuard in site.js. pointer-events:none keeps it from ever blocking
   the download button or video controls underneath. */
.preview-guard { position: absolute; inset: 0; pointer-events: none; z-index: 5; background-repeat: repeat; }
/* the little "?" that explains the preview marking (2026-07-21) — sits above the guard,
   clickable, discreet; only added for viewers who actually see the marking (site.js). */
.preview-guard-help {
  position: absolute; top: 6px; left: 6px; z-index: 6;
  width: 22px; height: 22px; padding: 0; border: 0; border-radius: 50%;
  font: 700 13px/22px Arial, sans-serif; text-align: center; cursor: pointer;
  background: rgba(0,0,0,.45); color: #fff; opacity: .6; transition: opacity .15s;
}
.preview-guard-help:hover, .preview-guard-help:focus-visible { opacity: 1; }

/* ---- tool / content card (homogeneous container, rule 3) ---- */
.tool {
  position: relative;
  background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius); padding: 24px 22px 22px;
  box-shadow: 0 1px 2px var(--shadow-sm), 0 14px 38px -18px var(--shadow-lg);
  overflow: hidden;
}
.tool::before {
  content: "";
  position: absolute; top: 0; left: 0; right: 0; height: 3px;
  background: linear-gradient(90deg, var(--accent), var(--accent2));
}
.eyebrow {
  font-family: var(--mono); font-size: 12px; color: var(--accent-ink); letter-spacing: .04em;
  display: inline-flex; align-items: center; gap: 7px;
  background: color-mix(in srgb, var(--accent) 10%, transparent);
  padding: 3px 10px; border-radius: 999px;
}
h1 { font-size: 26px; line-height: 1.15; letter-spacing: -.02em; margin: 6px 0 6px; }
.lede { color: var(--muted); margin: 0 0 18px; max-width: 60ch; }

/* ---- de leuze (2026-07-30) --------------------------------------------------
   Vijf woorden die samen BURDA spellen; het acroniem IS de merknaam, dus de
   beginletters moeten er visueel uitspringen zonder dat de zin schreeuwt.
   Ze staan als <b> in de vertaling, hier alleen gekleurd — nooit als losse
   letters in de markup, want dan zou een schermlezer ze los oplezen. */
.slogan {
  font-family: var(--mono);
  font-size: 13.5px; letter-spacing: .01em;
  color: var(--muted);
  margin: 8px 0 0;
}
.slogan b { color: var(--accent-ink); font-weight: 700; }
/* Alleen Turks heeft een sluitregel ("Hepsi burda." = alles is hier, de merknaam
   zelf). Leeg in de andere talen, dan rendert de regel niet. */
.slogan-tag {
  font-family: var(--mono); font-size: 12.5px; color: var(--accent-ink);
  margin: 3px 0 0; opacity: .85;
}
/* Bewust ZONDER opacity: met .8 zakte deze regel naar 3,45:1 in het lichte thema
   (gemeten), en dat is onder de norm van 4,5. Kleiner mag, bleker niet. */
.slogan-foot { margin: 0 0 12px; font-size: 12.5px; }
/* De cursor van het typ-effect. Hij hoort bij de animatie, niet bij de tekst,
   dus aria-hidden in de JS. */
.slogan .cur {
  display: inline-block; width: .55ch; margin-inline-start: 1px;
  background: var(--accent); animation: slogan-blink 1s steps(2) infinite;
  color: transparent;
}
@keyframes slogan-blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }
/* Wie beweging heeft uitgezet, krijgt de regel meteen compleet — de JS toont hem
   dan ook in één keer, dit is het vangnet voor het geval de animatie al liep. */
@media (prefers-reduced-motion: reduce) {
  .slogan .ch { opacity: 1 !important; }
  .slogan .cur { display: none; }
}
/* Quiet "use our API" note for CAD conversion pages (sister site apimycad.com). Muted,
   left-accent aside — informative, not an ad banner. */
.api-note { margin: 16px 0 0; padding: 12px 14px; border: 1px solid var(--line); border-left: 3px solid var(--accent);
  border-radius: 8px; background: color-mix(in srgb, var(--accent) 5%, var(--paper)); font-size: 13.5px; color: var(--muted); max-width: 62ch; }
.api-note strong { display: block; color: var(--ink); font-size: 14px; margin-bottom: 3px; }
.api-note a { color: var(--accent); text-decoration: none; white-space: nowrap; margin-left: 4px; font-weight: 600; }
.api-note a:hover { text-decoration: underline; }

.drop {
  border: 2px dashed var(--line); border-radius: 10px; padding: 30px 18px; text-align: center;
  background: color-mix(in srgb, var(--paper) 92%, var(--bg)); transition: border-color .15s, background .15s, box-shadow .15s; cursor: pointer;
  display: block;
}
.drop.drag { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, var(--paper)); }
/* action zones light up in the primary accent so the eye goes straight to them */
.drop:hover, .drop:focus-visible {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
.drop strong { display: block; font-size: 15px; }
.drop small { color: var(--muted); }
/* ---- compact source row (2026-07-18, Fikret's "1 foto to rule them all"):
   the big dashed box ate the top of every tool page. It becomes one modest
   button — and where a tool already has its own source buttons (microphone /
   add audio file) it disappears entirely, because those buttons load the file
   themselves. Dragging still works: the WHOLE tool card is the drop target
   (site.js), so the habit survives without costing any space. */
.drop.drop-compact {
  display: inline-flex; align-items: center; gap: 8px;
  border: 1px solid var(--line); border-style: solid; border-width: 1px;
  padding: 9px 16px; text-align: start; min-width: 230px; width: auto;
  background: color-mix(in srgb, var(--accent) 7%, var(--paper));
}
.drop.drop-compact::before { content: '📂'; font-size: 15px; line-height: 1; }
.drop.drop-compact strong { display: inline; font-size: 14px; font-weight: 600; }
.drop.drop-compact small { display: none; } /* the hint moves to the tooltip */
.drop.drop-hidden { display: none; }
/* the source buttons sit on one line, left-aligned, a touch roomier */
.src-row { margin: 12px 0; gap: 10px; }
.src-row .ghost, .src-row .cb-mic, .src-row .cb-mic-add { min-width: 190px; justify-content: center; padding: 9px 16px; }
/* the card itself lights up while a file is dragged over it */
/* .cbw is het werkvlak van de desktop-app: daar staat de bediening buiten de
   .tool-kaart, dus moet die de sleepmarkering krijgen. Op het web bestaat .cbw
   niet, dus daar verandert er niets. */
.tool.drag-over, .cbw.drag-over { outline: 2px dashed var(--accent); outline-offset: 6px; }
input[type=file] { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }

.row { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin: 14px 0; }

/* ---------- editor workspace: canvas left, one properties panel right ----------
   (Fikret 2026-07-15) Stacking every control BELOW a 74vh canvas meant you could never
   see the photo and the slider you were dragging at the same time — by the time you
   scrolled to "Size", half the image was gone. So the controls move beside the canvas,
   the model every real editor uses (he works in Photopea). One panel, not two: one
   place to look, and the canvas keeps the full remaining width.
   Shared classes, not per-page CSS — Image transparency and Cut out shapes reuse these
   verbatim, so the three tools cannot drift apart. */
.editor { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 14px; align-items: start; }
.editor-canvas { min-width: 0; }
/* Deliberately NO max-height/overflow here: a scrollbar inside the panel hid "Flatten &
   download" below its own fold — re-creating, in miniature, the exact bug this layout
   exists to kill. The panel is simply as tall as its contents; if that runs a little past
   the canvas, that costs a few pixels of page, not a lost button. */
.editor-panel {
  display: flex; flex-direction: column; gap: 9px;
  padding: 12px; border: 1px solid var(--line); border-radius: 8px;
  background: color-mix(in srgb, var(--accent2) 3%, var(--paper));
}
/* one control per block: caption line on top, the control itself below it full width */
.pfield { display: flex; flex-direction: column; gap: 5px; }
.plabel { font-size: 13px; color: var(--muted); display: flex; align-items: center; gap: 6px; }
.pval { margin-inline-start: auto; font-family: var(--mono); font-size: 12px; color: var(--ink); }
.panel-sep { border: 0; border-top: 1px solid var(--line); margin: 3px 0; width: 100%; }
.edge-check { display: flex; align-items: center; gap: 8px; cursor: pointer; font-size: 13.5px; color: var(--ink); }
.edge-check input { flex-shrink: 0; }
.editor-panel label.fld { width: 100%; gap: 6px; }
.editor-panel label.fld input[type=range] { flex: 1 1 auto; min-width: 0; }
/* image-transparency ships its own hold-to-repeat stepper wrapper — let it fill the column too */
.editor-panel .stepper { display: flex; width: 100%; }
.editor-panel .stepper input[type=range] { flex: 1 1 auto; min-width: 0; }
/* rows inside the panel are stacked, not spaced out like full-width page rows */
.editor-panel .row { margin: 0; gap: 6px; }
/* The shape library is the one genuinely long list here — 22 buttons across four groups
   would otherwise stretch the panel to double the canvas. It scrolls on its own so the
   picker stays browsable while Apply/Download below it stay put. This is a scrollable
   LIST, not a hidden action — the rule it must not break is that no button disappears. */
#csShapePanel { max-height: 300px; overflow-y: auto; padding-inline-end: 4px; }
.editor-panel select { width: 100%; }
.editor-panel .full { width: 100%; text-align: center; }
.editor-panel .help-btn { margin-inline-start: 0; flex: none; }
.editor-panel .hint-text { font-size: 12.5px; line-height: 1.45; }
/* the panel is only a panel while there is room beside the canvas; below that it becomes
   an ordinary stacked block again (phones were never going to get a side column) */
@media (max-width: 900px) {
  .editor { grid-template-columns: minmax(0, 1fr); }
}

/* Fixed-size viewport (Fikret 2026-07-12): the box never grows/shrinks with the zoom
   level — the canvas zooms INSIDE it, centered while it fits, scrollable once it doesn't. */
#tCanvasWrap { width: 100%; height: 74vh; overflow: auto; border-radius: 8px; border: 1px solid var(--line); background: var(--paper); display: flex; }
/* Dezelfde precisie-aanwijzer voor élk werkscherm (ronde 12). Color Replacer,
   Cut out shapes en Photo montage stonden op de kale systeempijl — je zag niet
   waar je precies klikte. Eén regel, geen kopieën die uit elkaar kunnen groeien. */
#tCanvasWrap canvas, #rCanvasWrap canvas, #csCanvasWrap canvas, #pmCanvasWrap canvas {
  display: block; flex: none; margin: auto;
  cursor:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='21' height='21' viewBox='0 0 21 21'%3E%3Cg stroke='white' stroke-width='3' stroke-linecap='square'%3E%3Cline x1='10.5' y1='1' x2='10.5' y2='8'/%3E%3Cline x1='10.5' y1='13' x2='10.5' y2='20'/%3E%3Cline x1='1' y1='10.5' x2='8' y2='10.5'/%3E%3Cline x1='13' y1='10.5' x2='20' y2='10.5'/%3E%3C/g%3E%3Cg stroke='black' stroke-width='1' stroke-linecap='square'%3E%3Cline x1='10.5' y1='1' x2='10.5' y2='8'/%3E%3Cline x1='10.5' y1='13' x2='10.5' y2='20'/%3E%3Cline x1='1' y1='10.5' x2='8' y2='10.5'/%3E%3Cline x1='13' y1='10.5' x2='20' y2='10.5'/%3E%3C/g%3E%3Ccircle cx='10.5' cy='10.5' r='1' fill='red'/%3E%3C/svg%3E")
    10 10, crosshair;
}
#tCanvasWrap canvas.panning { cursor: grabbing; }

/* Photo Studio (2026-07-19): same fixed zoom viewport as the transparency tool,
   plus a colour-swatch palette for the drawing panel. */
/* Het veld rondom het blad is bewust een tint donkerder dan papier (zelfde model
   als #dsViewWrap in de Document Studio): wit-op-wit gaf onvindbare bladgrenzen
   (Fikret 2026-08-01: "de bladgrenzen zijn te onduidelijk"). Het blad zelf
   (het canvas) draagt het schaakbord — transparante delen lezen dan als
   transparant i.p.v. als wit — plus een schaduw, zodat het als een vel papier
   op het veld ligt, hoe wit de inhoud ook is. */
#psCanvasWrap { position: relative; width: 100%; height: 74vh; overflow: auto; border-radius: 8px; border: 1px solid var(--line); background: var(--line); display: flex; }
#psCanvasWrap canvas {
  display: block; flex: none; margin: auto; touch-action: none;
  background-color: var(--paper);
  background-image:
    linear-gradient(45deg, var(--line) 25%, transparent 25%),
    linear-gradient(-45deg, var(--line) 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, var(--line) 75%),
    linear-gradient(-45deg, transparent 75%, var(--line) 75%);
  background-size: 20px 20px;
  background-position: 0 0, 0 10px, 10px -10px, -10px 0;
  box-shadow: 0 1px 2px var(--shadow-sm), 0 10px 26px -14px var(--shadow-lg);
}
/* Tekstvak (ronde 13): een echt tekstveld precies over het getrokken kader, zodat
   cursor, selectie, plakken en IME gewoon werken. Het ligt IN het scrollende
   venster, dus het schuift mee met de tekening; lettertype/grootte/kleur worden
   in JS gelijkgezet aan wat er straks gebakken wordt. */
#psCanvasWrap .ps-textbox {
    position: absolute; z-index: 3; margin: 0; padding: 0; resize: none; overflow: hidden;
    background: color-mix(in srgb, var(--paper) 62%, transparent);
    border: 1px dashed var(--accent2); border-radius: 2px;
    outline: 2px solid color-mix(in srgb, var(--accent2) 35%, transparent);
}

/* Color Replacer (ronde 12): dit venster had als enige nooit een eigen regel —
   dus geen vaste hoogte, geen overflow, geen scrollbalken. Inzoomen liet de
   tekening gewoon buiten het kader groeien en verschuiven was daardoor
   onmogelijk (Fikret: "pannen gaat totaal niet, en er verschijnen ook geen
   scrollbalken"). Zelfde venster als de andere werkschermen, één regel erbij. */
#rCanvasWrap { width: 100%; height: 74vh; overflow: auto; border-radius: 8px; border: 1px solid var(--line); background: var(--paper); display: flex; }
#rCanvasWrap canvas { display: block; flex: none; margin: auto; touch-action: none; }
.ps-swatches { display: flex; flex-wrap: wrap; gap: 5px; margin: 4px 0; }
.ps-swatch { width: 22px; height: 22px; border-radius: 5px; border: 1px solid var(--line); padding: 0; cursor: pointer; }
.ps-tools { display: flex; flex-wrap: wrap; gap: 6px; }
.ps-tools .ghost { padding: 5px 10px; }
/* Gedeeld bibliotheekpaneel (cbUserLib, 2026-07-31) — vormen, stickers, geluiden,
   kaders, handtekeningen en sjablonen zien er hierdoor overal hetzelfde uit.
   Het zoekveld en de knoppen staan BUITEN de scroller: een lijst mag scrollen,
   een knop mag nooit uit beeld verdwijnen. */
.cb-ul { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.cb-ul-zoek { width: 100%; box-sizing: border-box; }
.cb-ul-body { max-height: 300px; overflow-y: auto; overflow-x: hidden; padding-inline-end: 2px; }
.cb-ul-kop { margin: 8px 0 4px; }
.cb-ul-kop:first-child { margin-top: 0; }
.cb-ul-items { display: flex; flex-wrap: wrap; gap: 6px; }
.cb-ul-item { display: inline-flex; align-items: center; max-width: 100%; }
.cb-ul-item .cb-ul-pick { max-width: 210px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cb-ul-item.actief .cb-ul-pick { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, var(--paper)); }
.cb-ul-star, .cb-ul-mini { padding: 2px 6px; font-size: 12px; margin-inline-start: -2px; opacity: .55; }
.cb-ul-star:hover, .cb-ul-mini:hover, .cb-ul-star:focus-visible, .cb-ul-mini:focus-visible { opacity: 1; }
.cb-ul-star.aan { opacity: 1; color: var(--accent); }
.cb-ul-item.bewerk { gap: 4px; flex-wrap: wrap; }
.cb-ul-in { font-size: 13px; padding: 5px 8px; width: 120px; }
.cb-ul-leeg, .cb-ul-meld { margin: 6px 0; }
.cb-ul-acts { flex-wrap: wrap; gap: 6px; }
.cb-ul-verborgen { display: none !important; }
/* Regels in plaats van chips zodra een item meer dan een naam draagt (geluiden:
   beluisteren én plaatsen; handtekeningen: een beeldje). Twee knoppen achter een
   naam lopen anders over elkaar heen. */
.cb-ul-rijen { flex-direction: column; flex-wrap: nowrap; gap: 3px; }
.cb-ul-rijen .cb-ul-item { display: flex; width: 100%; gap: 2px; }
.cb-ul-rijen .cb-ul-item .cb-ul-pick { flex: 1; min-width: 0; max-width: none; text-align: start; }
/* Een inklapbare groepskop: volle breedte, want hij is de klikzone. */
.cb-ul-cat { width: 100%; text-align: start; font-size: 12.5px; padding: 5px 9px; }
/* Beeldje boven de naam — drie krabbels uit elkaar houden lukt niet op naam alleen. */
.cb-ul-thumb { display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 4px 6px; }
.cb-ul-thumb img { max-width: 96px; max-height: 40px; display: block; }
.cb-ul-thumb small { font-size: 11px; opacity: .75; max-width: 96px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ps-ctx { position: fixed; z-index: 60; background: var(--paper); border: 1px solid var(--line); border-radius: 8px; box-shadow: 0 6px 14px var(--shadow-sm), 0 22px 50px -24px var(--shadow-lg); display: flex; flex-direction: column; padding: 4px; min-width: 130px; }
.ps-ctx button { text-align: start; background: none; border: 0; padding: 6px 12px; border-radius: 5px; cursor: pointer; color: inherit; font-size: 13px; }
.ps-ctx button:hover:not(:disabled) { background: var(--line); }
.ps-ctx button:disabled { opacity: .4; cursor: default; }
/* shortcuts sheet (round 11): rebindable tool rows + the fixed reference list */
.ps-key-row { display: flex; align-items: center; gap: 10px; width: 100%; text-align: start; margin: 2px 0; }
.ps-key-row code { min-width: 34px; text-align: center; }
.ps-keys-fixed { display: grid; grid-template-columns: auto 1fr; gap: 4px 10px; align-items: baseline; }
.ps-ctx hr { border: 0; border-top: 1px solid var(--line); margin: 4px 6px; }
/* flyout with tool variants (line/brush/shape families) - same family as .ps-ctx */
.ps-flyout { position: fixed; z-index: 60; background: var(--paper); border: 1px solid var(--line); border-radius: 8px; box-shadow: 0 6px 14px var(--shadow-sm), 0 22px 50px -24px var(--shadow-lg); display: flex; flex-direction: column; gap: 2px; padding: 4px; min-width: 150px; }
.ps-flyout .ghost { text-align: start; justify-content: flex-start; }

/* image-to-dxf threshold preview: same fixed-viewport zoom/pan pattern */
#vPreviewWrap { width: 100%; height: 70vh; overflow: auto; border-radius: 8px; border: 1px solid var(--line); background: var(--paper); display: flex; margin-top: 10px; }
#vPreviewWrap canvas { display: block; flex: none; margin: auto; }
#vPreviewWrap canvas.panning { cursor: grabbing; }

/* image-transparency: help popover */
.help-btn { width: 26px; height: 26px; padding: 0; margin-inline-start: 8px; border-radius: 50%; font-weight: 700; display: inline-flex; align-items: center; justify-content: center; vertical-align: middle; }
.help-panel { margin: 10px 0 0; padding: 14px 16px; border: 1px solid var(--line); border-radius: 8px; background: color-mix(in srgb, var(--accent2) 6%, var(--paper)); }
.help-panel ul { margin: 8px 0 0; padding-inline-start: 20px; }
.help-panel li { margin: 4px 0; font-size: 14px; color: var(--ink); }

/* image-transparency: slider stepper +/- */
.stepper { display: inline-flex; align-items: center; gap: 6px; }
.stepper-btn { width: 26px; height: 26px; padding: 0; display: inline-flex; align-items: center; justify-content: center; font-size: 16px; line-height: 1; user-select: none; }

/* image-transparency: right-click context menu */
.context-menu {
  position: fixed; z-index: 60; min-width: 190px; padding: 6px;
  background: var(--paper); border: 1px solid var(--line); border-radius: 10px;
  box-shadow: 0 1px 2px var(--shadow-sm), 0 14px 38px -14px var(--shadow-lg);
}
.context-menu button {
  display: block; width: 100%; text-align: start; background: none; border: none;
  padding: 8px 10px; border-radius: 6px; cursor: pointer; font: inherit; font-size: 14px; color: var(--ink);
}
.context-menu button:hover, .context-menu button:focus-visible { background: color-mix(in srgb, var(--accent2) 12%, transparent); }

.meta.warn { color: var(--accent-ink); }
.btn {
  background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 100%, white 8%), var(--accent));
  color: #211404; border: none; padding: 10px 16px; border-radius: 8px; font: inherit; font-weight: 600;
  cursor: pointer; text-decoration: none; display: inline-block;
  box-shadow: 0 6px 14px -8px color-mix(in srgb, var(--accent) 70%, transparent);
  transition: transform .1s ease, box-shadow .1s ease, filter .1s ease;
}
.btn:hover { filter: brightness(1.04); transform: translateY(-1px); box-shadow: 0 8px 18px -8px color-mix(in srgb, var(--accent) 75%, transparent); }
.btn[disabled] { opacity: .45; cursor: not-allowed; transform: none; box-shadow: none; }
input[type=range] { font: inherit; }
/* Fikret 2026-07-15, standing rule: EVERY slider gets − / + steppers so a value can be
   nudged exactly instead of fought with by dragging (and it's far kinder on a phone).
   site.js injects them automatically around every <input type=range> — no per-page markup. */
.ghost.range-step {
  flex: none; padding: 0; width: 28px; min-width: 28px; height: 28px;
  font-size: 15px; font-weight: 700; line-height: 1; border-radius: 7px;
  display: inline-flex; align-items: center; justify-content: center;
}
/* Fikret's crypto-page input style promoted to the site-wide standard (2026-07-10):
   soft filled fields, rounded, with a colored focus glow */
select,
input[type=text],
input[type=number],
input[type=password],
input[type=search],
textarea {
  appearance: none;
  -webkit-appearance: none;
  background: var(--bg); border: 1px solid transparent; border-radius: 10px;
  padding: 9px 13px; font: inherit; font-size: 15px; color: var(--ink); outline: none;
  transition: border-color .15s ease, background .15s ease, box-shadow .15s ease;
}
select:focus,
input[type=text]:focus,
input[type=number]:focus,
input[type=password]:focus,
input[type=search]:focus {
  border-color: var(--accent2); background: var(--paper);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent2) 18%, transparent);
}
select {
  padding-right: 32px; cursor: pointer; font-weight: 500;
  /* arrow color = --muted; data-URIs can't read CSS variables, hence the literal */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%235b6673'%3E%3Cpath d='M7 10l5 5 5-5z'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 10px center; background-size: 20px;
}
textarea {
  font-family: var(--mono); font-size: 13px; width: 100%; min-height: 160px; resize: vertical;
}
/* the big text areas light up in the PRIMARY accent (Fikret's focus rule) */
textarea:focus {
  border-color: var(--accent); background: var(--paper);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
label.fld { font-size: 14px; color: var(--muted); display: flex; align-items: center; gap: 8px; }
.unit-tag { color: var(--muted); font-size: 13px; font-weight: 400; }

/* code viewer */
.code { border: 1px solid var(--line); border-radius: 8px; overflow: auto; max-height: 420px; background: #0e141b; }
.code table { border-collapse: collapse; width: 100%; font-family: var(--mono); font-size: 13px; }
.code td { padding: 1px 10px; white-space: pre; vertical-align: top; }
.code td.ln { color: #5a6b7d; text-align: right; user-select: none; background: #0b1016; position: sticky; left: 0; width: 1%; }
.code td.src { color: #d6e2ee; }
.tok-g { color: #7fd1ff; }
.tok-m { color: #ffb86b; }
.tok-axis { color: #a6e3a1; }
.tok-fs { color: #f2c56b; }
.tok-n { color: #6a7d8f; }
.tok-com { color: #6a7d8f; font-style: italic; }
.tok-num { color: #e6edf3; }

/* light data table (results, reference values) */
.table-wrap { overflow-x: auto; margin-top: 12px; }
.table { border-collapse: collapse; width: 100%; font-size: 14px; }
.table td { padding: 7px 10px; border-bottom: 1px solid var(--line); }
.table tr:first-child td { border-top: 1px solid var(--line); }
.table td:last-child { text-align: right; font-family: var(--mono); }

.meta { font-family: var(--mono); font-size: 12px; color: var(--muted); margin-top: 10px; }
.result-ok, .result-bad { border-radius: 8px; padding: 12px 14px; font-size: 14px; }
.result-ok { background: color-mix(in srgb, var(--ok) 12%, white); border: 1px solid var(--ok); color: var(--ok); }
.result-bad { background: color-mix(in srgb, var(--danger) 10%, white); border: 1px solid var(--danger); color: var(--danger); }
.preview { margin-top: 12px; border: 1px solid var(--line); border-radius: 8px; padding: 10px; background: #fbfcfe; text-align: center; }
.preview img { max-width: 100%; max-height: 320px; border-radius: 4px; }
/* the desktop app draws the tool glyph itself next to the OS pointer (the WebView2
   host renders no CSS cursor images — and Fikret wants the glyphs, 2026-08-01) */
.ps-cursor-ghost { position: fixed; z-index: 70; width: 28px; height: 28px; pointer-events: none; }
/* checkerboard = the universal "this has transparency" indicator (Photoshop/GIMP convention) —
   without it, a transparent PNG previewed on this near-white box looks identical to an opaque
   white one, so a successful transparency removal looked like it had done nothing at all. */
.preview.checkerboard {
  background-color: var(--paper);
  background-image:
    linear-gradient(45deg, var(--line) 25%, transparent 25%),
    linear-gradient(-45deg, var(--line) 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, var(--line) 75%),
    linear-gradient(-45deg, transparent 75%, var(--line) 75%);
  background-size: 20px 20px;
  background-position: 0 0, 0 10px, 10px -10px, -10px 0;
}

/* shared result preview (result-preview.js, 2026-07-26): the uniform
   Preview → Save output flow of the image tools. The view box has a bounded
   height and the image opens on FIT — the whole result is always visible,
   never cut off; scroll = zoom, and the Save button sits under the preview
   (sticky, so it can never scroll out of a docked panel in the app). */
.cb-rp { margin-top: 12px; }
.cb-rp-view {
  height: clamp(220px, 44vh, 560px);
  overflow: auto;
  display: flex;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--paper);
}
.cb-rp-view img { margin: auto; display: block; border-radius: 2px; }
.cb-rp-view img.cb-rp-pix { image-rendering: pixelated; }
.cb-rp-view.checkerboard {
  background-color: var(--paper);
  background-image:
    linear-gradient(45deg, var(--line) 25%, transparent 25%),
    linear-gradient(-45deg, var(--line) 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, var(--line) 75%),
    linear-gradient(-45deg, transparent 75%, var(--line) 75%);
  background-size: 20px 20px;
  background-position: 0 0, 0 10px, 10px -10px, -10px 0;
}
.cb-rp-bar { display: flex; align-items: center; gap: 6px; margin-top: 6px; flex-wrap: wrap; }
.cb-rp-bar .ghost { min-width: 34px; }
.cb-rp-cap { margin: 0; margin-inline-start: auto; }
.cb-rp-save {
  position: sticky; bottom: 0;
  display: flex; justify-content: flex-end;
  padding: 8px 0 2px;
  background: var(--paper);
}

/* explainer under the tool (SEO copy) — its own card, not transparent-on-grid */
.explain {
  margin-top: 22px; background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 20px 22px; box-shadow: 0 1px 2px var(--shadow-sm);
}
.explain h2 { font-size: 16px; margin: 0 0 8px; color: var(--ink); }
.explain h2:not(:first-child) { margin-top: 18px; }
.explain h3 { font-size: 14.5px; margin: 20px 0 6px; color: var(--ink); }
.explain p { color: var(--muted); margin: 0 0 14px; max-width: 70ch; }
details { border: 1px solid var(--line); border-radius: 8px; padding: 10px 14px; margin-bottom: 8px; background: color-mix(in srgb, var(--ad-bg) 60%, white); }
details:hover { border-color: var(--accent); }
summary { cursor: pointer; font-weight: 600; font-size: 14px; }
details p { margin: 8px 0 2px; }

/* ---- waveform editor (shared audio-tool component, 2026-07-16) ---- */
.wave-editor { margin-top: 12px; }
.wave-editor .we-canvas-wrap {
  position: relative; /* anchors the hold-down time readout (2026-07-17) */
  border: 1px solid var(--line); border-radius: 8px; overflow: hidden;
  background: color-mix(in srgb, var(--accent2) 4%, var(--paper));
}
/* exact time (m:ss.mmm) while the pointer is held on the band (Fikret's video) */
.we-timetip {
  position: absolute; top: 4px; pointer-events: none;
  background: color-mix(in srgb, var(--ink) 85%, transparent); color: var(--paper);
  font-family: var(--mono); font-size: 11px; padding: 2px 7px; border-radius: 6px;
}
.wave-editor .we-zoom { display: inline-flex; gap: 4px; margin-inline-start: auto; }
.wave-editor canvas { display: block; width: 100%; cursor: crosshair; touch-action: none; }
.wave-editor .we-top { align-items: center; gap: 10px; margin-bottom: 6px; }
.wave-editor .we-play { min-width: 42px; }
.wave-editor .we-hint { margin: 6px 0 4px; }
.wave-editor .we-sel { flex-wrap: wrap; gap: 10px; align-items: flex-end; }
.wave-editor .we-fld { display: flex; flex-direction: column; gap: 4px; font-size: 13px; }
.wave-editor .we-zones-h { font-size: 14px; margin: 12px 0 4px; }
.wave-editor .we-zone { align-items: center; gap: 8px; padding: 4px 0; border-top: 1px solid var(--line); }
.wave-editor .we-chip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 6px; color: #fff; font-weight: 700; font-size: 12px; flex: none;
}
.wave-editor .we-err { margin: 6px 0; }
.wave-editor .we-vad { align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
/* inline per-zone edit slider (zones adjustable after the fact, 2026-07-17) */
.we-zone-edit { flex-direction: row !important; align-items: center; gap: 6px; }
.we-zone-edit input[type=range] { width: 110px; }
/* recordings shelf under the mic button (2026-07-17) */
.we-shelf { margin-top: 10px; }
.we-shelf .we-zone { flex-wrap: wrap; }
/* added-audio tracks (2026-07-17): each take is its own sound bar under the main
   waveform — drag on the lane selects a part, the row below places it */
.cb-track { border: 1px solid var(--line); border-radius: 8px; padding: 6px 12px; margin: 8px 0; background: var(--paper); }
.cb-track-lane { border: 1px solid var(--line); border-radius: 6px; overflow: hidden; background: color-mix(in srgb, var(--accent2) 5%, var(--paper)); cursor: crosshair; }
.cb-track-lane canvas { display: block; width: 100%; }
.cb-track .row { margin: 6px 0 0; flex-wrap: wrap; gap: 8px; align-items: center; }
.cb-track p.meta { margin: 6px 0 0; font-size: 12px; }
/* compact tracks (Fikret's video 3:57): a closed track is one thin head line;
   ▸/▾ (or a double click on the head) folds the lane + controls open/shut */
.cb-track .cb-track-body { display: none; }
.cb-track.open .cb-track-body { display: block; }
.cb-track > .row:first-child { margin: 0; }
/* result waveform under the player (2026-07-17) */
/* a strip-click on the band highlights the matching placed-piece row */
.we-piece-flash { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 6px; }

/* ---- floating "?" hint box (2026-07-17, Fikret's mime video: opening a hint
   pushed the page down — now it is a compact fixed box, zero reflow) ---- */
#cbHintPop {
  position: fixed; z-index: 70; max-width: 300px;
  background: var(--paper); border: 1px solid var(--line); border-radius: 8px;
  box-shadow: 0 2px 6px var(--shadow-sm), 0 12px 32px -12px var(--shadow-lg);
  padding: 8px 11px; font-size: 12.5px; line-height: 1.45; color: var(--muted);
  white-space: pre-line; /* merged hints separate their topics with a blank line */
}
/* the bigger help panels float the same way when opened (any .help-panel) */
.help-pop {
  position: fixed; z-index: 70; margin: 0;
  width: min(440px, calc(100vw - 16px)); max-height: 60vh; overflow: auto;
  box-shadow: 0 2px 6px var(--shadow-sm), 0 12px 32px -12px var(--shadow-lg);
}

/* ---- studio layout (CBCOM Audio Mixer, Fikret's video reviews 2026-07-17:
   "we maken een app, geen tool" → workspace at the very top, extra wide; round
   2: no big website card but loose ISLANDS, bands stacked tightly) */
/* No dedicated ad column any more (2026-07-20: the ad moved to the shared, fixed-
   position .ad-rail in _Layout — see site.css's "the one ad slot" block) — the
   studio simply gets its full 1400px of workspace, always, ad-free plan or not. */
.wrap-studio { max-width: 1400px; }
/* the studio drops the .tool card chrome — the islands ARE the surfaces */
.tool.studio { background: transparent; border: 0; box-shadow: none; padding: 0; overflow: visible; }
.tool.studio::before { display: none; }
.tool.studio h1.studio-h1 { font-size: 20px; margin: 4px 0 8px; }
.mx-island { margin: 0 0 8px; align-items: center; gap: 12px; }
.mx-island > .row { margin: 0; }
/* compact source island instead of the big drop box */
.drop.mini { padding: 10px 16px; display: inline-block; text-align: start; background: var(--paper); }
.drop.mini strong { font-size: 14px; }
/* the band stack: tight full-width sound bars, straight below each other */
.mx-band { margin: 6px 0; }
.mx-band .wave-editor { margin-top: 0; }
.mx-band .we-top { margin-bottom: 2px; }
/* the highlighted band receives edits/placements (shown with >1 band) */
.mx-band.active .we-canvas-wrap { border-color: var(--accent); box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 22%, transparent); }
/* filename in small contrast letters ON the bar itself (end of the bar) */
.we-bandlabel {
  position: absolute; top: 4px; right: 6px; display: inline-flex; align-items: center; gap: 6px;
  background: color-mix(in srgb, var(--ink) 78%, transparent); color: var(--paper);
  font-family: var(--mono); font-size: 11px; padding: 2px 4px 2px 8px; border-radius: 6px;
}
.we-bandlabel .we-bandx {
  background: none; border: 0; color: inherit; cursor: pointer; font-size: 11px; padding: 0 4px; line-height: 1;
}
.we-bandlabel .we-bandx:hover { color: var(--accent); }
/* M/S toggles on the bar (v10, classic mixer) — lit = active */
.we-bandlabel .we-bandbtn { font-weight: 700; border-radius: 4px; padding: 1px 5px; opacity: .75; }
.we-bandlabel .we-bandbtn.on { background: var(--accent); color: #fff; opacity: 1; }
/* loop toggle next to ▶ (v10) — lit when looping */
.wave-editor .we-loop.on { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 18%, var(--paper)); }
/* active transport states (v13): playing ▶, and the ⏪/⏩ shuttle showing its speed */
.wave-editor .we-play.on, .wave-editor .we-shuttle.on,
#vsPlay.on, #vsFfw.on, #vsFbw.on { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 16%, var(--paper)); }
/* ---- islands: loose panels, each closable, back via the Panels menu ---- */
.mx-islands { display: flex; flex-wrap: wrap; gap: 12px; align-items: flex-start; margin-top: 10px; }

/* video studio: the picture is the centre of the program, so the stage gets the
   width and the panels sit underneath it (same .isl framework as audio) */
/* The stage is resizable like the islands (drag the bottom-right corner) so the
   picture can be shrunk out of the way while working in the panels; the ⤢
   button in the transport puts it back to full width. The canvas scales INSIDE
   whatever size the stage has — never clipped (Fikret, 2026-07-19). */
.vs-stage { display: flex; justify-content: center; align-items: center; background: #000; border-radius: 12px; overflow: hidden; resize: both; min-width: 240px; min-height: 135px; max-width: 100%; }
/* Shrinking the stage frees the space NEXT to it: the islands (camera panel,
   record button) flow up beside the picture instead of staying below the fold.
   Full-width stage → islands simply wrap underneath, the old layout.
   display:contents — the islands are FREE flex items of .vs-work, not a pinned
   right-hand column (Fikret: "vastgepind... ze moeten vrij in te delen zijn"):
   they flow beside the stage, wrap into full rows below, and stay individually
   draggable/resizable. */
.vs-work { display: flex; flex-wrap: wrap; gap: 14px; align-items: flex-start; }
.vs-work .vs-main { flex: 0 1 auto; min-width: 240px; max-width: 100%; }
.vs-work .mx-islands { display: contents; }
/* The export buttons must NEVER scroll away inside a resized island — a
   scrolling list is fine, a vanishing button is not (Fikret's "export knop is
   er niet meer": scrolled above the island's own scrollbar). */
.vs-out-actions { position: sticky; top: 0; background: var(--paper); z-index: 2; padding-bottom: 6px; }
/* audio-studio equivalent: preview/bitrate row pins while the result scrolls */
.mx-out-actions { position: sticky; top: 0; background: var(--paper); z-index: 2; padding-bottom: 6px; }
/* Every format shows as a viewport-bounded miniature (Fikret 2026-07-21: a phone or
   square format used to blow up to full pixel size — 720×1280 — and overflow the page
   instead of scaling down like a small phone next to a 17" screen). A vh max-height
   guarantees the scale-down for ANY aspect ratio, independent of the parent's height. */
/* V4: the picture is a player — normal cursor by default; JS shows a move cursor
   only while hovering a draggable overlay. */
.vs-stage canvas { max-width: 100%; max-height: 78vh; width: auto; height: auto; display: block; cursor: default; touch-action: none; }
/* the ⤢ button toggles this compact view so the stage can be shrunk back with one click */
.vs-stage.vs-compact canvas { max-height: 44vh; }
/* Double-tap the picture → real full screen (V4). Force the stage to fill the
   screen even if a corner-drag left an inline width, and let the canvas use the
   whole height. */
.vs-stage:fullscreen { width: 100vw !important; height: 100vh !important; max-width: none !important; resize: none; border-radius: 0; }
.vs-stage:fullscreen canvas { max-height: 100vh; }
/* live stage-record button while rolling: unmistakably red so you never leave it running */
#vsRecStage.rec-on { color: #fff; background: #d32f2f; border-color: #d32f2f; }
/* the camera/screen preview in the record panel: scale with the island instead
   of clipping to a quarter of the picture when the island is made smaller */
.vs-cam { max-width: 100%; height: auto; display: block; border-radius: 8px; }
/* one picture at a time: while the live feed owns the MAIN stage the panel
   preview moves off-screen (NOT display:none — the canvas must keep painting
   for captureStream). It returns the moment a clip takes the stage. */
.vs-cam-off { position: absolute; left: -10000px; top: 0; }
.vs-row { border: 1px solid var(--line); border-radius: 10px; padding: 6px 8px; margin-bottom: 6px; }
.vs-row .pfield { margin: 4px 0 0; }
/* the clip you picked on the visual timeline is the clip marked in the list —
   one selection, two views (ronde C) */
.vs-row.sel { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }

/* ── Video Studio: the visual timeline (ronde C) ──────────────────────────
   Clip blocks to scale, the audio tracks and the overlays underneath, and a
   playhead that runs along. Click or drag to move the playhead, wheel to scrub;
   hovering shows a miniature of that exact moment. */
.vs-tl { position: relative; margin: 0 0 10px; user-select: none; touch-action: none; cursor: pointer; }
.vs-tl-lane {
  position: relative; height: 26px; margin-bottom: 3px; border-radius: 6px;
  background: color-mix(in srgb, var(--ink) 7%, var(--paper));
  border: 1px solid var(--line); overflow: hidden;
}
.vs-tl-lane.thin { height: 11px; }
.vs-tl-b {
  position: absolute; top: 0; bottom: 0; border-radius: 5px; overflow: hidden;
  font-size: 10px; line-height: 24px; padding: 0 5px; white-space: nowrap; text-overflow: ellipsis;
  color: var(--ink); border: 1px solid color-mix(in srgb, var(--accent2) 55%, var(--line));
  background: color-mix(in srgb, var(--accent2) 18%, var(--paper));
}
.vs-tl-b.sel { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 24%, var(--paper)); }
.vs-tl-b.audio { background: color-mix(in srgb, var(--accent3) 26%, var(--paper)); border-color: color-mix(in srgb, var(--accent3) 55%, var(--line)); }
.vs-tl-b.ov { background: color-mix(in srgb, var(--accent) 20%, var(--paper)); border-color: color-mix(in srgb, var(--accent) 45%, var(--line)); }
/* the cut itself: a hairline exactly where one clip hands over to the next */
.vs-tl-cut { position: absolute; top: 0; bottom: 0; width: 1px; background: var(--ink); opacity: .45; }
.vs-tl-head { position: absolute; top: -3px; bottom: 0; width: 2px; background: var(--accent); pointer-events: none; z-index: 3; }
.vs-tl-head::before {
  content: ''; position: absolute; top: 0; left: -4px;
  border: 5px solid transparent; border-top-color: var(--accent);
}
.vs-tl-tip {
  position: fixed; z-index: 60; transform: translate(-50%, -104%);
  background: var(--ink); color: var(--paper); padding: 4px; border-radius: 7px;
  pointer-events: none; box-shadow: 0 2px 8px var(--shadow-sm);
}
.vs-tl-tip img { display: block; width: 160px; height: auto; border-radius: 4px; background: #000; }
.vs-tl-tip span { display: block; text-align: center; margin-top: 3px; font: 600 11px var(--mono, ui-monospace, monospace); }
/* Edit island: knob-EQ far LEFT as a vertical column, motors to its right
   (Fikret round 6 — much more compact) */
.mx-edit-cols { display: flex; gap: 14px; align-items: flex-start; flex-wrap: wrap; }
.mx-edit-left { flex: 1 1 320px; min-width: 0; }
.mx-eqcorner {
  flex: 0 0 auto; text-align: center; padding: 8px 10px;
  border: 1px solid var(--line); border-radius: 10px;
  background: color-mix(in srgb, var(--accent2) 5%, var(--paper));
}
.mx-knob-col { display: flex; flex-direction: column; gap: 8px; align-items: center; margin-top: 4px; }

/* ---- alleen in de desktop-app: de EQ-doos kantelt mee met de kolombreedte ----
   In de app bepaalt de DOKKOLOM de breedte van een eiland, en die versleep je.
   Werd de kolom smal, dan brak de EQ af naar zijn eigen regel: een pilaar van
   68 px breed en 352 px hoog, met de hele breedte ernaast leeg. Het eiland werd
   daardoor 3,5x zo hoog als in de brede stand, en bij het omslagpunt sprong er
   in één sleepstap 346 px hoogte weg — Fikrets "de eilanden verspringen te veel"
   (gemeten 2026-07-31).
     • row wrap: de VORM volgt de breedte. Smalle doos = één knop per regel, dus
       exact de verticale kolom van ronde 6; brede doos = alle vier naast elkaar.
     • groei 100 tegen 1: naast de motoren krijgt de EQ ~1% van de vrije ruimte
       (2 px, gemeten), maar alleen op zijn eigen regel pakt hij alles — en juist
       dát laat de knoppen kantelen. Geen container-query nodig.
     • basis 68px = de natuurlijke breedte van één knop plus padding. Met 90 lag
       het omslagpunt verkeerd en werd de BREDE stand 10-62 px hoger.
   Bewust NIET op de website: daar is dit eiland `wideId`, dus zijn breedte komt
   van zijn INHOUD — en de max-content van een rij knoppen is 208 px in plaats
   van 46, waardoor het eiland daar 595 -> 757 px werd. In de app kan dat niet
   gebeuren, want daar geeft `.cbw-dock > .isl { width: auto !important }` de
   breedte aan de kolom. */
html.cb-app-layout .mx-edit-left { flex: 100 1 320px; }
html.cb-app-layout .mx-eqcorner { flex: 1 1 68px; }
html.cb-app-layout .mx-knob-col { flex-flow: row wrap; justify-content: center; }
/* anti-jitter (Fikret round 6): the value label has a FIXED width and the slider
   a fixed length, so 100→99 or a minus sign can never push anything around */
.mx-val { display: inline-block; width: 52px; flex: none; font-family: var(--mono); font-size: 11px; text-align: end; }
/* explicit reset-to-neutral pill next to the live sliders (layout-brief §14):
   shows the literal neutral value (100% / 0 st / 1x / 0), lands exactly there */
/* Vaste breedte, en dat is geen versiering: de vier pillen dragen "100%", "0 st",
   "1x" en "0" en waren dus 40/40/28/22 px breed, waardoor elke motorrij bij een
   ANDERE kolombreedte omklapte (350/360/370). Dat trapje is wat je ziet als je
   de kolom versleept. De bedoelde min-width van 34 haalde het niet van
   `.isl-b .ghost { min-width: 0 }` verderop; `width` wordt door niets betwist.
   Gemeten 2026-07-31: hiermee klappen de vier rijen samen om, in één stap. */
.mx-zero { flex: none; font-size: 11px; padding: 2px 4px; width: 44px; font-family: var(--mono); }
.mx-motor input[type=range], #mxFxList input[type=range] { width: 150px; flex: none; }
.mx-motor .meta { min-width: 92px; flex: none; }
.mx-knob { display: flex; flex-direction: column; align-items: center; width: 46px; }
.mx-knob-dial {
  width: 36px; height: 36px; border-radius: 50%; cursor: ns-resize; touch-action: none;
  border: 2px solid var(--line); position: relative;
  background: radial-gradient(circle at 35% 30%, color-mix(in srgb, var(--paper) 70%, #fff), var(--paper));
}
.mx-knob-dial::after {
  content: ""; position: absolute; left: 50%; top: 3px; width: 2px; height: 11px;
  background: var(--accent); border-radius: 2px;
  transform-origin: 50% 15px; transform: translateX(-50%) rotate(var(--rot, 0deg));
}
.mx-knob-dial:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.mx-knob-cap { font-size: 11px; font-weight: 700; margin-top: 3px; }
.mx-knob-val { font-size: 10px; color: var(--muted); font-family: var(--mono); }
/* library rows and the synth keyboard */
.mx-keys { display: flex; gap: 3px; flex-wrap: wrap; margin: 8px 0 4px; }
.mx-key { min-width: 30px; padding: 12px 4px 6px; font-size: 11px; }
.mx-key.sharp { background: color-mix(in srgb, var(--ink) 82%, var(--paper)); color: var(--paper); }
.mx-seq { min-height: 18px; font-family: var(--mono); font-size: 12px; word-break: break-word; }
.isl {
  background: var(--paper); border: 1px solid var(--line); border-radius: 10px;
  box-shadow: 0 1px 2px var(--shadow-sm), 0 10px 26px -18px var(--shadow-lg);
  padding: 8px 12px 10px; flex: 0 0 auto; min-width: 220px; max-width: 100%;
  /* v11: every panel is user-resizable (native grip, bottom corner); a panel
     made smaller than its content scrolls — the 🗖 button jumps to full size */
  resize: both; overflow: auto; min-height: 40px;
}
/* Touch-friendly resize grip (studio-shell adds the element). Hidden on desktop —
   the native corner grip is kept there; shown only where a finger needs it, and
   the native handle is turned off so there is no dead double-grip. */
.isl-grip { display: none; position: absolute; right: 2px; bottom: 2px; width: 22px; height: 22px;
  cursor: nwse-resize; touch-action: none; z-index: 3; opacity: .55;
  background:
    linear-gradient(135deg, transparent 45%, var(--muted) 45%, var(--muted) 55%, transparent 55%,
    transparent 66%, var(--muted) 66%, var(--muted) 76%, transparent 76%); }
@media (pointer: coarse) {
  .isl { resize: none; position: relative; }
  .isl-grip { display: block; }
}
.isl-wide { flex: 0 0 auto; } /* v11: no special width — all panels default alike */
.isl-h { display: flex; align-items: center; gap: 6px; margin-bottom: 2px; cursor: grab; user-select: none; touch-action: none; }
/* the title takes the free space so ?/🗖/✕ always sit TOGETHER at the end
   (v11 fix: space-between spread them across the whole width) */
.isl-h > span:first-child { font-weight: 700; font-size: 13px; flex: 1 1 auto; min-width: 0; }
/* a panel being dragged to a new spot (grab it by its title bar) */
.isl-dragging { opacity: .75; outline: 2px dashed var(--accent); outline-offset: 2px; }
.isl-x { padding: 2px 8px; font-size: 12px; }
.isl-mm { font-size: 11px; } /* 🗖 grow-to-content / 🗕 back-to-own-size (v11) */
/* ---- polish round (2026-07-18): three button weights, not one grey wall.
   .primary = the action this panel is FOR, .danger = removes audio.
   Both keep the ghost shape, so the family stays recognisable. */
.ghost.primary {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, var(--paper));
  color: var(--ink); font-weight: 700;
}
.ghost.primary:hover { background: color-mix(in srgb, var(--accent) 24%, var(--paper)); }
.ghost.danger { color: color-mix(in srgb, #d33 70%, var(--ink)); }
.ghost.danger:hover { border-color: #d33; background: color-mix(in srgb, #d33 10%, var(--paper)); }
/* an empty panel says so in one dim line instead of being a blank box */
.isl-b[data-empty]:empty::before {
  content: attr(data-empty);
  display: block; padding: 6px 2px; font-size: 12px; color: var(--muted); font-style: italic;
}
/* v12: the record-the-mix button turns red while a take is running */
#mxRecOut.rec-on { border-color: #d33; color: #d33; font-weight: 700; font-family: var(--mono); }
/* ---- v13: Winamp-style player deck. Deliberately its OWN retro skin with
   fixed colours (the CodeQuest precedent: a product identity, not site chrome) */
.mx-wamp-lcd { background: #0a1608; border: 1px solid #1d3a18; border-radius: 6px; padding: 6px 10px; font-family: var(--mono); color: #7dff6e; }
.mx-wamp-title { font-size: 12px; white-space: nowrap; overflow: hidden; }
/* v14: a title wider than the LCD crawls past, like the original. Only applied
   when it actually overflows, and never under prefers-reduced-motion (the JS
   decides; this class is what it toggles). */
.mx-wamp-title.scroll > span { display: inline-block; padding-inline-end: 3em; animation: mx-wamp-marquee 12s linear infinite; }
@keyframes mx-wamp-marquee { from { transform: translateX(0); } to { transform: translateX(-100%); } }
.mx-wamp-time { font-size: 11px; opacity: .8; display: flex; justify-content: space-between; gap: 8px; }
.mx-wamp-row { gap: 6px; align-items: flex-end; flex-wrap: wrap; }
.mx-wamp-btn { padding: 4px 10px; font-size: 13px; }
.mx-wamp-mode { font-size: 11px; padding: 4px 8px; }
.mx-wamp-mode.on { border-color: #2f9b3a; color: #1d7a27; background: color-mix(in srgb, #2f9b3a 12%, var(--paper)); }
.mx-wamp-seek { width: 100%; margin: 6px 0 2px; }
.mx-wamp-eq { font-size: 11px; }
.mx-wamp-eq input[type=range] { width: 64px; }
/* v14: the spectrum analyser. Fixed retro colours like the rest of the deck. */
.mx-wamp-vis { display: block; width: 100%; height: 64px; margin: 6px 0 2px; border: 1px solid #1d3a18; border-radius: 6px; background: #0a1608; }
/* v14: the playlist is a real list — number, title, time, and a total underneath */
.mx-pl { max-height: 190px; overflow-y: auto; border: 1px solid var(--line); border-radius: 8px; margin-top: 6px; }
.mx-pl-row { display: flex; align-items: center; gap: 8px; padding: 3px 6px; font-size: 12px; cursor: pointer; }
.mx-pl-row + .mx-pl-row { border-top: 1px solid color-mix(in srgb, var(--line) 60%, transparent); }
.mx-pl-row:hover { background: color-mix(in srgb, var(--ink) 6%, transparent); }
.mx-pl-row.on { background: color-mix(in srgb, var(--accent) 16%, transparent); font-weight: 600; }
.mx-pl-no { font-family: var(--mono); color: var(--muted); min-width: 2.2em; text-align: end; }
.mx-pl-nm { flex: 1 1 auto; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.mx-pl-t { font-family: var(--mono); color: var(--muted); font-size: 11px; }
.mx-pl-x { padding: 1px 6px; font-size: 11px; line-height: 1.4; }
.mx-pl-foot { font-size: 11px; color: var(--muted); font-family: var(--mono); padding: 4px 2px 0; }
.mx-pl-empty { font-size: 12px; color: var(--muted); font-style: italic; padding: 6px 2px; }
/* v14 maximised: deck left, playlist right, and the analyser takes what is left.
   position:fixed covers the work area — in the app that is the iframe, so the
   menu bar stays reachable. */
.mx-wamp-full {
  position: fixed; inset: 8px; z-index: 60;
  display: flex; flex-direction: column;
  background: var(--paper); border: 1px solid var(--line); border-radius: 12px;
  padding: 12px; overflow: hidden;
  box-shadow: 0 6px 14px var(--shadow-sm), 0 28px 70px -28px var(--shadow-lg);
}
/* De twee kolommen. Alleen DIT deel scrollt, dus de kopbalk erboven kan nooit
   uit beeld raken — een uitgang die wegscrolt is geen uitgang. */
.mx-wamp-full .mx-wamp-cols {
  flex: 1 1 auto; min-height: 0; overflow: auto;
  display: grid; gap: 12px; grid-template-columns: minmax(0, 1fr) minmax(240px, 34%);
}
/* De kopbalk van de grote stand: naam links, uitgang MET WOORD rechts
   (Fikret 2026-07-31 — een kaal pictogram onderaan vond hij niet terug). */
.mx-wamp-bar { display: none; }
.mx-wamp-full .mx-wamp-bar {
  flex: 0 0 auto;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin: -12px -12px 10px; padding: 8px 12px;
  background: var(--paper); border-bottom: 1px solid var(--line);
}
.mx-wamp-bar-t { font-weight: 600; }
.mx-wamp-full .mx-wamp-deck { display: flex; flex-direction: column; min-height: 0; }
.mx-wamp-full .mx-wamp-vis { flex: 1 1 auto; height: auto; min-height: 120px; }
.mx-wamp-full .mx-wamp-pl { display: flex; flex-direction: column; min-height: 0; }
.mx-wamp-full .mx-pl { flex: 1 1 auto; max-height: none; }
.mx-wamp-full .mx-wamp-title { font-size: 15px; }
@media (max-width: 700px) { .mx-wamp-full .mx-wamp-cols { grid-template-columns: minmax(0, 1fr); } }
/* the popped-out player floats above the page and drags anywhere */
.isl-float { position: fixed; z-index: 30; box-shadow: 0 6px 14px var(--shadow-sm), 0 28px 70px -28px var(--shadow-lg); }
.isl-fb { padding: 2px 8px; font-size: 11px; }
/* v13: library categories (collapsible) + loop badge + synth key caps */
.mx-lib-cat { display: block; width: 100%; text-align: start; font-weight: 700; margin-top: 6px; }
.mx-lib-items { margin: 2px 0 4px; }
.mx-lib-loop { font-size: 12px; }
#isl-library .isl-b { max-height: 360px; overflow-y: auto; }
.mx-key small { display: block; font-size: 9px; opacity: .65; line-height: 1; min-height: 9px; }
.mx-key.on { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 18%, var(--paper)); }
/* ---- voice changer (2026-07-18): preset tiles, icon + word (never colour alone) */
.vc-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 8px; width: 100%; }
.vc-preset { display: flex; align-items: center; gap: 8px; text-align: start; padding: 8px 10px; }
.vc-preset .vc-ic { font-size: 18px; line-height: 1; }
.vc-preset.on { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, var(--paper)); font-weight: 700; }
/* the "add audio file" button stays: with the drop box gone (2026-07-18) it IS
   the file loader here — on a page without a main file it feeds the main input */
.isl-h .help-btn { padding: 0 7px; font-size: 12px; } /* the "?" after the title */
.isl-b .row { margin: 8px 0; }
/* ---- island-internal layout hardening (2026-07-26, Fikret: "niks overlapt en
   alles altijd duidelijk zichtbaar en gebruikbaar hoe smal het ook ingesteld is").
   Measured before this block: up to 209 px of controls clipped off the island's
   edge at the DEFAULT width — sliders + their −/+ steppers sat in a no-wrap
   label row, and buttons could not shrink below their text (min-width:auto).
   Rules: every control may shrink (min-width:0) and wraps instead of sticking
   out; a slider is flexible within its row, never the fixed ~129 px default. */
.isl-b, .isl-b .fld { min-width: 0; }
.isl-b .ghost, .isl-b .btn { max-width: 100%; min-width: 0; white-space: normal; }
.isl-b .full { width: 100%; text-align: center; }
.isl-b select, .isl-b input[type=text], .isl-b input[type=number],
.isl-b textarea { max-width: 100%; min-width: 0; }
.isl-b label.fld { flex-wrap: wrap; row-gap: 3px; }
.isl-b label.fld > input[type=range] { flex: 1 1 60px; min-width: 36px; width: auto; }
.isl-b label.fld > select, .isl-b label.fld > input[type=text] { flex: 1 1 auto; }
/* the pfield pattern: caption (text + value badge) on its own line ABOVE the
   control — studio-shell's tidyFlds wraps the caption in .fld-t */
.isl-b label.fld > .fld-t { flex: 1 0 100%; display: flex; align-items: baseline; gap: 6px; min-width: 0; }
.isl-b label.fld > .fld-t .meta { margin-inline-start: auto; flex: none; }
/* ---- document tabs above the work canvas (GIF frames = tabs, 2026-07-26).
   Hidden until a second tab exists, so a single-document page looks unchanged. */
.cb-doc-tabs { display: flex; flex-wrap: wrap; gap: 4px; align-items: flex-end; margin: 0 0 6px; }
.cb-doc-tab {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px; max-width: 190px;
  border: 1px solid var(--line); border-radius: 8px 8px 0 0;
  background: none; color: var(--ink); font: inherit; font-size: 12.5px; cursor: pointer;
}
.cb-doc-tab > span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.cb-doc-tab.on { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, var(--paper)); font-weight: 700; }
.cb-tab-dot { color: var(--accent); font-weight: 700; flex: none; }
.cb-tab-x { opacity: .55; padding: 0 2px; flex: none; }
.cb-tab-x:hover { opacity: 1; }
.cb-tab-plus { padding: 4px 9px; font-weight: 700; }
.mx-motor { gap: 8px; align-items: center; }
.mx-motor .meta { min-width: 84px; }
/* Panels menu chips (closed islands come back from here) */
.mx-isl-menu { margin: 8px 0 0; gap: 6px; align-items: center; }
.isl-chip { font-size: 12px; padding: 4px 10px; opacity: .55; }
.isl-chip.on { opacity: 1; border-color: var(--accent); }
.isl-menu-btn { font-size: 15px; padding: 4px 9px; }
/* Aa = de eilanden breed of compact (studio-shell.js). Alleen de knoppen die
   studio-shell écht heeft ingekort dragen data-cb-glyph, dus een knop die zijn
   woorden hield krijgt hier geen vierkante maat opgedrongen. */
.isl-names { font-size: 13px; font-weight: 700; opacity: .75; }
.isl-names:hover, .isl-names[aria-pressed="true"] { opacity: 1; }
.isl-compact .isl-b button[data-cb-glyph] {
  min-width: 34px; padding-inline: 8px; text-align: center;
}
.mx-isl-menu.chips-folded .isl-chip { display: none; }
/* Sounds / Recordings: small compact lists (quarter-B5 feel) — a scrolling LIST
   is fine, a disappearing button is not (the standing panel rule) */
/* Detection island stays COMPACT in use (Fikret round 9: it tripled in size
   once the status sentence appeared and shoved the other panels around) —
   status lines are small blocks, buttons wrap, the voice list runs vertically.
   (v11: the old max-width caps are gone — panels are user-resizable and get a
   340px DEFAULT width from JS instead, so growing past it stays possible.) */
#isl-detect .isl-b { font-size: 12px; }
#isl-detect .ghost { padding: 4px 9px; font-size: 12px; }
.mx-det-st { display: block; font-size: 12px; color: var(--muted); margin: 5px 0 2px; }
.mx-det-sens { display: flex; align-items: center; gap: 6px; font-size: 12px; margin: 6px 0 0; cursor: pointer; }
.mx-det-sens input { width: auto; margin: 0; }
.mx-det-acts { flex-wrap: wrap; gap: 6px; }
.mx-spk { border-top: 1px dashed var(--line); padding-top: 6px; margin-top: 8px; }
.mx-spk .row { margin: 4px 0; gap: 6px; align-items: center; }
.mx-spk .meta { flex: 1 1 auto; }
.mx-spk input[type=range] { width: 96px; }
.mx-spk select { font-size: 12px; padding: 3px 6px; width: auto; }
/* the FX-block list may grow (voice edits add one block per segment) —
   a scrolling LIST is fine, a disappearing button is not */
#mxFxList { max-height: 220px; overflow-y: auto; }
#isl-sounds .isl-b, #isl-records .isl-b { max-height: 240px; overflow-y: auto; font-size: 12px; }
#isl-sounds .cb-track, #isl-records .cb-track { padding: 3px 8px; margin: 5px 0; }
#isl-sounds .cb-track .meta, #isl-records .cb-track .meta { font-size: 12px; }
#isl-sounds .cb-track .ghost, #isl-records .cb-track .ghost { padding: 3px 8px; font-size: 12px; }
.we-static { border: 1px solid var(--line); border-radius: 8px; overflow: hidden; margin: 8px 0; background: color-mix(in srgb, var(--accent2) 4%, var(--paper)); }
.we-static canvas { display: block; width: 100%; }

/* ---- /pricing page ---- */
/* regional-pricing note (world tiers, 2026-07-16) — only rendered for tier 2/3 visitors */
.geo-note { color: var(--accent2); font-weight: 600; }
.coming-soon-banner {
  background: color-mix(in srgb, var(--accent2) 10%, var(--paper));
  border-color: color-mix(in srgb, var(--accent2) 35%, var(--line));
}
.price-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 14px; margin-top: 6px; }
.price-card {
  border: 1px solid var(--line); border-radius: 10px; padding: 16px; background: var(--paper);
  text-decoration: none; color: inherit; display: block; transition: border-color .15s, transform .15s;
}
a.price-card:hover { border-color: var(--accent); transform: translateY(-2px); }
.price-card h3 { margin: 0 0 10px; font-size: 15px; }
.price-card .examples { color: var(--muted); font-size: 12.5px; margin: 8px 0 0; }
.price-card .big-price { display: block; font-size: 26px; margin: 4px 0; }
.price-card.featured-card { border-color: var(--accent); box-shadow: 0 6px 18px -10px color-mix(in srgb, var(--accent) 60%, transparent); }
/* Sub-heading inside a section that holds several price grids (the buy-once groups). */
.buy-group { margin: 22px 0 2px; font-size: 14px; color: var(--muted); font-weight: 600; letter-spacing: .02em; }
.buy-group:first-of-type { margin-top: 14px; }
.badge-free, .badge-owned {
  display: inline-block; font-size: 11px; font-weight: 600; letter-spacing: .03em; text-transform: uppercase;
  color: var(--ok); background: color-mix(in srgb, var(--ok) 14%, transparent); border-radius: 6px; padding: 3px 8px; margin-bottom: 8px;
}
.badge-owned { text-transform: none; letter-spacing: 0; }
.badge-save {
  display: inline-block; font-size: 11px; font-weight: 600; color: var(--accent-ink);
  background: color-mix(in srgb, var(--accent) 18%, transparent); border-radius: 6px; padding: 2px 7px; margin-inline-end: 6px;
}
.price-card .durations { display: flex; gap: 8px; flex-wrap: wrap; }
.price-card .duration {
  flex: 1 1 0; min-width: 78px; text-align: center; border: 1px solid var(--line); border-radius: 8px; padding: 8px 6px;
}
.price-card .duration b { display: block; font-size: 16px; }
.price-card .duration span { display: block; font-size: 11px; color: var(--muted); }
.price-card .duration.featured { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, transparent); }
.price-card .duration span.badge-save { display: inline-block; color: var(--accent-ink); }
/* Day pass link, made a visible pill instead of plain fine-print text (Fikret
   2026-07-20: it existed but was too easy to scroll past). */
.daypass-link {
  display: block; margin-top: 10px; padding: 7px 10px; text-align: center;
  font-size: 12.5px; font-weight: 600; text-decoration: none; color: var(--accent-ink);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--line)); border-radius: 8px;
  transition: background .12s ease;
}
.daypass-link:hover { background: color-mix(in srgb, var(--accent) 20%, transparent); }
.combo-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px; margin-top: 6px; }
.combo-card { border: 1px solid var(--line); border-radius: 10px; padding: 14px; background: var(--paper); text-align: center; }
.combo-pair { font-size: 13px; color: var(--muted); margin-bottom: 8px; }
.combo-pair .plus { color: var(--accent-ink); font-weight: 700; margin: 0 4px; }
.combo-price s { color: var(--muted); font-size: 13px; margin-inline-end: 6px; }
.combo-price b { font-size: 19px; }
.combo-price span { color: var(--muted); font-size: 12px; }

/* ---- safety warning (machining calculators) ---- */
.safety-warning {
  display: flex; gap: 10px; align-items: flex-start; margin-top: 14px;
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--accent) 45%, var(--line));
  border-radius: 8px; padding: 12px 14px;
}
.safety-warning span { flex: none; font-size: 17px; line-height: 1.4; }
.safety-warning p { margin: 0; color: var(--ink); font-size: 13px; max-width: none; }

/* Before/after dimensions table (shrinkage scaler). */
.scale-table { border-collapse: collapse; margin-top: 6px; font-size: 13px; }
.scale-table td { border: 1px solid var(--line); padding: 4px 12px; text-align: right; }
.scale-table td:first-child { text-align: left; border: 0; padding-left: 0; }
.scale-table tr:first-child td { border: 0; color: var(--muted); font-size: 11px; text-align: right; }

/* Two coordinate inputs sharing one panel field row (DXF editor). */
.editor-panel label.fld input[type=number] { flex: 1 1 0; min-width: 0; }

/* ---- catalog grid (used on home + "more tools" sections) ---- */
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 12px; }
.card {
  border: 1px solid var(--line); border-radius: 8px; padding: 12px 13px; background: var(--paper); cursor: pointer;
  text-align: left; font: inherit; text-decoration: none; color: inherit; display: block;
  transition: transform .12s ease, box-shadow .12s ease, border-color .12s ease;
}
.card:hover { border-color: var(--accent); transform: translateY(-2px); box-shadow: 0 8px 18px -12px var(--shadow-lg); }
.card .t { font-weight: 600; font-size: 14px; }
.card .d { color: var(--muted); font-size: 12.5px; margin-top: 2px; }
.card .tag { display: inline-block; margin-top: 8px; font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase; color: #93a0af; }
.card.soon { opacity: .72; cursor: default; }

/* ---- homepage hero + segments ---- */
/* richer than a plain card — reinforces "this is a product" on the very first thing seen */
.hero {
  position: relative; overflow: visible;
  background: linear-gradient(160deg, color-mix(in srgb, var(--accent) 8%, var(--paper)), color-mix(in srgb, var(--accent2) 6%, var(--paper)) 75%);
}
.hero h1 { max-width: 24ch; }
.hero .lede { max-width: 56ch; }
/* The big logo is a transparent PNG since 2026-07-13 (Fikret's square version)
   and floats directly on BOTH themes — Fikret checked it on a dark surface
   himself ("het is niet zo erg als je denkt") and dropped the dark-mode badge. */
:root { --biglogo-bg: transparent; }
/* 200->300px (2026-07-21, Fikret: +50% on the mainpage) — the brand-card version
   elsewhere on every tool page keeps its own, larger 420px size unchanged. It also
   gently floats now (the "flying" feel Fikret asked for); disabled for reduced-motion. */
.hero-logo { display: block; max-width: 300px; width: 100%; height: auto; margin: 0 auto 14px; padding: 10px; box-sizing: border-box; background: var(--biglogo-bg); border-radius: 12px; animation: cb-float 5.5s ease-in-out infinite; }
@keyframes cb-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } }

/* ---- interactive hero accordion (2026-07-21, Fikret's "flying info bar") ----
   The hero blurb sits fixed on the left and ALWAYS shows its full content — it never
   reacts to hover, and (crucially) it defines the row height so nothing ever moves
   vertically. The three feature panels share the rest; hovering one widens it and
   reveals its text, taking room only from its two siblings. Their descriptions are
   absolutely positioned, so revealing one can NEVER change the row height — the page
   below stays perfectly still (Fikret: "hou ze in toom"). Touch/narrow → plain stack. */
.hero-accordion { display: flex; gap: 10px; margin-top: 4px; align-items: stretch; }
.hp {
  position: relative; display: flex; flex-direction: column; gap: 6px;
  min-width: 0; overflow: hidden;
  padding: 18px; border-radius: 14px; text-align: left;
  border: 1px solid var(--line);
  background: color-mix(in srgb, var(--accent) 5%, var(--paper));
  transition: flex-grow .4s cubic-bezier(.2, .7, .2, 1), box-shadow .25s ease;
}
/* the hero tile: fixed width, full content always, inert to hover */
.hp-hero { flex: 0 0 42%; background: linear-gradient(160deg, color-mix(in srgb, var(--accent) 12%, var(--paper)), color-mix(in srgb, var(--accent2) 8%, var(--paper)) 80%); }
/* the three feature tiles share the remaining width; the hovered one grows, its two
   siblings shrink — the hero and everything below are untouched */
.hp-f1, .hp-f2, .hp-f3 { flex: 1 1 0; }
.hp-f1:hover, .hp-f2:hover, .hp-f3:hover { flex-grow: 2.6; box-shadow: 0 12px 34px -14px var(--shadow-lg); }
.hp-head { display: flex; gap: 12px; align-items: flex-start; }
.hp-icon {
  flex: none; width: 44px; height: 44px; border-radius: 11px;
  display: flex; align-items: center; justify-content: center;
  color: var(--accent-ink); background: color-mix(in srgb, var(--accent) 18%, var(--paper));
}
.hp-icon svg { width: 24px; height: 24px; }
.hp-f2 .hp-icon { color: var(--accent2-ink); background: color-mix(in srgb, var(--accent2) 18%, var(--paper)); }
.hp-f3 .hp-icon { color: var(--accent3-ink); background: color-mix(in srgb, var(--accent3) 18%, var(--paper)); }
.hp .eyebrow { margin: 0; }
.hp h1 { font-size: clamp(20px, 2.3vw, 30px); margin: 3px 0 0; line-height: 1.15; }
.hp h2 { font-size: 16.5px; margin: 8px 0 0; }
/* hero description: normal flow, always visible — it sets the constant row height */
.hp-hero .hp-desc .lede { margin: 0; }
/* feature descriptions: absolutely positioned so they add ZERO height; fade in only
   when that tile is hovered. Because they never affect layout, the row can't grow. */
.hp-f1 .hp-desc, .hp-f2 .hp-desc, .hp-f3 .hp-desc {
  position: absolute; left: 18px; right: 14px; top: 76px;
  opacity: 0; transition: opacity .25s ease; pointer-events: none;
}
.hp-f1:hover .hp-desc, .hp-f2:hover .hp-desc, .hp-f3:hover .hp-desc { opacity: 1; }
.hp-desc p { margin: 0; color: var(--muted); font-size: 14px; }
.hero-badge {
  display: inline-flex; align-items: center; gap: 6px; align-self: flex-start;
  margin-top: 14px; padding: 7px 15px; border-radius: 999px;
  font-weight: 700; font-size: 14px; color: #fff;
  background: linear-gradient(90deg, var(--accent), var(--accent2));
  box-shadow: 0 8px 20px -8px var(--accent);
  animation: cb-pulse 2.4s ease-in-out infinite;
}
@keyframes cb-pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.06); } }
/* Touch devices (no hover) and phones: plain readable stack — every panel fully open,
   descriptions back in normal flow so nothing is clipped. */
@media (hover: none), (max-width: 720px) {
  .hero-accordion { flex-direction: column; }
  .hp-hero, .hp-f1, .hp-f2, .hp-f3 { flex: 1 1 auto; }
  .hp-f1 .hp-desc, .hp-f2 .hp-desc, .hp-f3 .hp-desc { position: static; opacity: 1 !important; margin-top: 8px; }
}
@media (prefers-reduced-motion: reduce) {
  .hero-logo, .hero-badge { animation: none; }
  .hp { transition: none; }
}

/* ---- quick-launch bar (2026-07-21, Fikret's "flying info bar") ----
   A slim sticky bar of studio + category chips. Hidden while the hero is in view;
   flies in when you scroll back UP past the hero, and gets out of the way when you
   scroll DOWN — so tools/software stay one click away without ever being in the way.
   Sits just under the sticky header (JS sets its `top` to the header height). */
.quicklaunch {
  position: fixed; left: 0; right: 0; z-index: 19;
  background: var(--header-bg); backdrop-filter: blur(6px);
  border-bottom: 1px solid var(--line);
  box-shadow: 0 10px 24px -16px var(--shadow-lg);
  transform: translateY(-140%);
  transition: transform .32s cubic-bezier(.2, .7, .2, 1);
  will-change: transform;
}
.quicklaunch.show { transform: translateY(0); }
.ql-inner { max-width: 1180px; margin: 0 auto; display: flex; gap: 8px; align-items: center; padding: 8px 12px; overflow-x: auto; scrollbar-width: thin; }
.ql-chip {
  flex: none; display: inline-flex; align-items: center; gap: 6px;
  padding: 6px 11px; border-radius: 999px; border: 1px solid var(--line);
  background: var(--paper); color: var(--ink); text-decoration: none;
  font-size: 13px; font-weight: 600; white-space: nowrap;
  transition: transform .15s ease, box-shadow .15s ease, border-color .15s ease;
}
.ql-chip:hover { transform: translateY(-1px); border-color: color-mix(in srgb, var(--accent) 50%, var(--line)); box-shadow: 0 6px 14px -8px var(--shadow-lg); }
.ql-chip .ql-i { font-size: 15px; line-height: 1; }
.ql-studio { border-color: color-mix(in srgb, var(--accent) 40%, var(--line)); background: color-mix(in srgb, var(--accent) 9%, var(--paper)); }
.ql-sep { flex: none; width: 1px; align-self: stretch; background: var(--line); margin: 3px 2px; }
@media (max-width: 700px) {
  .ql-inner { padding: 6px 8px; gap: 6px; }
  .ql-chip { font-size: 12px; padding: 5px 9px; }
}
@media (prefers-reduced-motion: reduce) { .quicklaunch { transition: none; } }

/* ---- help "vraagbaak" widget (2026-07-21) ----
   Bottom-LEFT on purpose: the ad rail lives on the right, so the launcher never
   overlaps an ad slot (AdSense accidental-click safety). */
.hb-launch {
  position: fixed; left: 18px; bottom: 18px; z-index: 30;
  width: 52px; height: 52px; border-radius: 50%; border: 1px solid var(--line);
  background: linear-gradient(160deg, var(--accent), var(--accent2)); color: #fff;
  font-size: 23px; line-height: 1; cursor: pointer; padding: 0;
  box-shadow: 0 10px 26px -10px var(--shadow-lg); transition: transform .15s ease, box-shadow .2s ease;
}
.hb-launch:hover { transform: translateY(-2px); box-shadow: 0 14px 32px -12px var(--shadow-lg); }
.hb-panel {
  position: fixed; left: 18px; bottom: 80px; z-index: 39;
  width: min(360px, calc(100vw - 24px)); max-height: min(70vh, 560px);
  display: none; flex-direction: column; overflow: hidden;
  background: var(--paper); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: 0 18px 50px -20px var(--shadow-lg), 0 6px 16px -8px var(--shadow-sm);
}
.hb-panel.open { display: flex; }
.hb-head { display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 12px 14px; font-weight: 700; color: #fff; background: linear-gradient(90deg, var(--accent), var(--accent2)); }
.hb-x { background: none; border: 0; color: #fff; font-size: 22px; line-height: 1; cursor: pointer; padding: 0 4px; }
.hb-body { padding: 12px 14px; overflow-y: auto; flex: 1; }
.hb-intro { margin: 0 0 10px; color: var(--muted); font-size: 13.5px; }
.hb-sugg { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 10px; }
.hb-chip { border: 1px solid var(--line); background: var(--paper); color: var(--ink);
  border-radius: 999px; padding: 5px 11px; font-size: 12.5px; cursor: pointer; text-align: start; }
.hb-chip:hover { border-color: color-mix(in srgb, var(--accent) 50%, var(--line)); }
.hb-answer .hb-a { margin: 0 0 8px; font-size: 14px; color: var(--ink); line-height: 1.5; }
.hb-answer .hb-th { margin: 8px 0 4px; font-weight: 700; font-size: 13px; }
.hb-tools { margin: 0; padding-inline-start: 18px; }
.hb-tools li { margin: 3px 0; font-size: 14px; }
.hb-form { display: flex; gap: 6px; padding: 10px 12px; border-top: 1px solid var(--line); }
.hb-input { flex: 1; min-width: 0; }
.hb-send { flex: none; padding: 0 12px; }
@media (max-width: 700px) {
  .hb-launch { width: 46px; height: 46px; font-size: 21px; left: 12px; bottom: 12px; }
  .hb-panel { left: 12px; right: 12px; bottom: 66px; width: auto; }
}
.brand-card { text-align: center; }
.brand-card img { max-width: 420px; width: 100%; height: auto; padding: 10px; box-sizing: border-box; background: var(--biglogo-bg); border-radius: 12px; }

.segments { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.segment { text-align: left; }
.segment h2 { font-size: 17px; margin: 4px 0 6px; }
.segment p { color: var(--muted); font-size: 14px; margin: 0 0 14px; }
.segment-icon {
  width: 40px; height: 40px; border-radius: 10px; display: flex; align-items: center; justify-content: center;
  color: var(--accent-ink); background: color-mix(in srgb, var(--accent) 16%, var(--paper));
}
.segment:nth-child(2) .segment-icon { color: var(--accent2-ink); background: color-mix(in srgb, var(--accent2) 16%, var(--paper)); }
.segment:nth-child(3) .segment-icon { color: var(--accent3-ink); background: color-mix(in srgb, var(--accent3) 16%, var(--paper)); }
.segment-icon svg { width: 21px; height: 21px; }

@media (max-width: 900px) {
  .segments { grid-template-columns: 1fr; }
}

/* homepage tool tiles — "LIT" pass (2026-07-12): each category gets its own color
   identity (icon badge + tinted section + tinted, left-accented cards) so scrolling
   through the homepage reads as moving through a designed product's sections, not a
   flat directory listing. Colors are moderate/professional, not neon — same shadow
   and radius language as every other card on the site (rule 3 homogeneity), only the
   hue changes per category. */
.cat-audio        { --cat: #7c5cbf; --cat-ink: #4a3380; }
.cat-video        { --cat: #c0524a; --cat-ink: #7a2f28; }
.cat-images       { --cat: var(--accent); --cat-ink: var(--accent-ink); }
.cat-pdf          { --cat: var(--accent2); --cat-ink: var(--accent2-ink); }
.cat-business     { --cat: #1f9e7c; --cat-ink: #0f5c46; }
.cat-cad          { --cat: #55708a; --cat-ink: #2e4155; }
.cat-dev          { --cat: #5a63c4; --cat-ink: #33397a; }
.cat-machining    { --cat: #a8672a; --cat-ink: #603a18; }
.cat-engineering  { --cat: #1f8fa3; --cat-ink: #0f4e59; }
:root[data-theme="dark"] .cat-audio       { --cat: #b09ee8; --cat-ink: #d8cff5; }
:root[data-theme="dark"] .cat-video       { --cat: #e2948c; --cat-ink: #f5d4d0; }
:root[data-theme="dark"] .cat-business    { --cat: #4dcda8; --cat-ink: #a8f0da; }
:root[data-theme="dark"] .cat-cad         { --cat: #9fb4c7; --cat-ink: #d3e0ea; }
:root[data-theme="dark"] .cat-dev         { --cat: #9ba3e8; --cat-ink: #d4d8f7; }
:root[data-theme="dark"] .cat-machining   { --cat: #d99b4f; --cat-ink: #f0cfa0; }
:root[data-theme="dark"] .cat-engineering { --cat: #5fc9dd; --cat-ink: #b8ecf5; }

.cat-icon {
  flex: none; width: 36px; height: 36px; border-radius: 10px; font-size: 18px;
  display: flex; align-items: center; justify-content: center;
  background: color-mix(in srgb, var(--cat, var(--accent)) 20%, var(--paper));
}
.tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 10px; }
.tile {
  display: block; padding: 12px 14px; border: 1px solid var(--line); border-radius: 8px;
  border-inline-start: 3px solid var(--cat, var(--accent));
  text-decoration: none; background: color-mix(in srgb, var(--cat, var(--accent)) 4%, var(--paper));
  transition: border-color .12s ease, transform .12s ease, box-shadow .12s ease, background .12s ease;
}
.tile:hover {
  border-color: var(--cat, var(--accent)); transform: translateY(-2px);
  background: color-mix(in srgb, var(--cat, var(--accent)) 9%, var(--paper));
  box-shadow: 0 10px 22px -12px color-mix(in srgb, var(--cat, var(--accent)) 55%, transparent);
}
.tile strong { display: block; color: var(--cat-ink, var(--ink)); font-size: 14.5px; margin-bottom: 2px; }
.tile span { color: var(--muted); font-size: 12.5px; line-height: 1.35; display: block; }
/* flagship tools (the CBCOM studios + the 2D CAD Drawpad) get a subtle "featured"
   highlight on the category tile grids (2026-07-21, Fikret): a full ring, a soft glow
   and a small ★ in the corner — noticeable but not loud. */
.tile.flagship {
  position: relative;
  border-color: var(--cat, var(--accent));
  background: color-mix(in srgb, var(--cat, var(--accent)) 10%, var(--paper));
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--cat, var(--accent)) 45%, transparent),
              0 8px 22px -14px color-mix(in srgb, var(--cat, var(--accent)) 60%, transparent);
}
.tile.flagship::after {
  content: "\2605"; position: absolute; top: 6px; inset-inline-end: 9px;
  font-size: 12px; line-height: 1; color: var(--cat, var(--accent)); opacity: .85;
}
.tile.flagship:hover { box-shadow: 0 12px 26px -12px color-mix(in srgb, var(--cat, var(--accent)) 60%, transparent); }

/* ---- homepage studio islands + category overview (2026-07-20 redesign) ----
   Replaces the old always-expanded 99-tile wall + on-page search: 3 richer studio
   cards, then 9 compact category cards, both target=_blank so a click never loses
   the homepage tab. Category cards reuse the .cat-* color tokens above (same family
   look as the /tools/{slug} pages' own .tile cards). */
.studios-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 16px; }
.studio-card { display: block; text-decoration: none; color: inherit; transition: transform .12s ease, box-shadow .12s ease; }
.studio-card:hover { transform: translateY(-3px); }
.studio-card .studio-icon { font-size: 34px; line-height: 1; margin-bottom: 8px; }
.studio-card h3 { margin: 0 0 6px; font-size: 17px; }
.studio-card p { margin: 0; color: var(--muted); font-size: 13.5px; }
.studio-card .newtab-hint, .cat-card .newtab-hint { display: block; margin-top: 10px; font-size: 11.5px; color: var(--muted); }

.cats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); gap: 14px; }
.cat-card {
  display: block; padding: 16px 16px 14px; border: 1px solid var(--line); border-radius: 10px;
  border-inline-start: 3px solid var(--cat, var(--accent));
  text-decoration: none; color: inherit;
  background: color-mix(in srgb, var(--cat, var(--accent)) 4%, var(--paper));
  transition: border-color .12s ease, transform .12s ease, box-shadow .12s ease, background .12s ease;
}
.cat-card:hover {
  border-color: var(--cat, var(--accent)); transform: translateY(-2px);
  background: color-mix(in srgb, var(--cat, var(--accent)) 9%, var(--paper));
  box-shadow: 0 10px 22px -12px color-mix(in srgb, var(--cat, var(--accent)) 55%, transparent);
}
.cat-card-top { display: flex; align-items: center; gap: 10px; margin-bottom: 6px; }
.cat-card h3 { margin: 0; font-size: 15.5px; color: var(--cat-ink, var(--ink)); flex: 1; min-width: 0; }
.cat-card .cat-count { font-size: 11px; font-weight: 600; color: var(--muted); flex: none; }
.cat-card p { margin: 0; color: var(--muted); font-size: 12.5px; line-height: 1.4; }

/* Gallery vs Index view (Fikret 2026-07-12): the base .tile styles above ARE the compact
   "Index view" (his personal favorite); the data-view="gallery" overrides below give new
   visitors the spacious tile look with a pictogram per tool. The pre-paint script in
   _Layout defaults to gallery; the header toggle (homepage only) flips and remembers it. */
.tile .tile-icon { display: none; } /* .tile .tile-icon (0-2-0) so it outranks the generic `.tile span` block rule above */
:root[data-view="gallery"] .tiles { grid-template-columns: repeat(auto-fill, minmax(215px, 1fr)); gap: 16px; }
:root[data-view="gallery"] .tile {
  text-align: center; padding: 20px 16px 16px;
  border-inline-start: 1px solid var(--line);
  border-top: 3px solid var(--cat, var(--accent));
}
:root[data-view="gallery"] .tile-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 48px; height: 48px; margin: 0 auto 10px; border-radius: 13px;
  color: var(--cat-ink, var(--accent-ink));
  background: color-mix(in srgb, var(--cat, var(--accent)) 15%, var(--paper));
}
:root[data-view="gallery"] .tile-icon svg { width: 27px; height: 27px; }
:root[data-view="gallery"] .tile strong { font-size: 15px; margin-bottom: 4px; }
:root[data-view="gallery"] .tile:hover .tile-icon {
  background: color-mix(in srgb, var(--cat, var(--accent)) 26%, var(--paper));
}

/* "quick cards" — Fikret's iPhone-style panel trial (crypto page first, 2026-07-10);
   his design, recolored onto our tokens (accent2 replaces iOS-blue, bg replaces iOS-grey) */
.top-controls { display: flex; flex-wrap: wrap; gap: 16px; margin-bottom: 20px; align-items: stretch; }
.ios-card {
  background: var(--paper); border-radius: 16px; padding: 16px 20px;
  border: 1px solid var(--line);
  box-shadow: 0 4px 14px -6px color-mix(in srgb, var(--ink) 18%, transparent);
  display: flex; flex-direction: column; justify-content: center;
}
.ios-card h2, .ios-card .eyebrow-label {
  margin: 0 0 10px; font-size: 13px; font-weight: 600; color: var(--muted);
  text-transform: uppercase; letter-spacing: .5px;
}
.converter-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
/* .ios-input/.ios-select need no own rules anymore — their style became the
   site-wide input/select standard (see the global rules above) */
.ios-equals { font-size: 20px; color: var(--muted); font-weight: 500; margin: 0 4px; }
.ios-label { font-size: 15px; font-weight: 600; color: var(--ink); }

/* related tools block on tool pages */
.related h2 { font-size: 15px; margin: 0 0 10px; }
.related-links { display: flex; flex-wrap: wrap; gap: 8px; }
.related-links .ghost { font-size: 13px; padding: 6px 11px; }
.related-links .ghost.pick {
  border-color: var(--accent); color: var(--accent-ink);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}
.pick-star { color: var(--accent-ink); margin-inline-end: 4px; }

/* site-wide footer sitemap */
.sitemap { border-top: 1px solid var(--line); background: var(--paper); }
.sitemap-in {
  max-width: 1180px; margin: 0 auto; padding: 22px 18px;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 16px;
}
.sitemap-col h3 { font-size: 12.5px; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); margin: 0 0 8px; }
.sitemap-col ul { list-style: none; margin: 0; padding: 0; }
.sitemap-col li { margin: 0 0 5px; }
.sitemap-col a { color: var(--ink); text-decoration: none; font-size: 13px; }
.sitemap-col a:hover { color: var(--accent-ink); text-decoration: underline; }

footer { max-width: 1180px; margin: 0 auto; padding: 26px 18px 50px; color: var(--muted); font-size: 13px; border-top: 1px solid var(--line); }
footer a { color: var(--muted); text-decoration: none; margin-inline-end: 14px; }
footer a:hover { color: var(--ink); }
footer button.linklike { background: none; border: none; padding: 0; margin-inline-end: 14px; color: var(--muted); font: inherit; cursor: pointer; text-decoration: none; }
footer button.linklike:hover { color: var(--ink); }

/* ---- modal (custom, never alert()/confirm() — rule 12; one at a time — rule 5) ---- */
.veil { position: fixed; inset: 0; background: rgba(17, 24, 32, .5); display: none; align-items: center; justify-content: center; z-index: 40; padding: 18px; }
.veil.open { display: flex; }
.modal { background: var(--paper); border-radius: 12px; max-width: 440px; width: 100%; padding: 24px; }
.modal h3 { margin: 0 0 6px; }
.modal p { color: var(--muted); font-size: 14px; }
.close { float: right; border: none; background: none; font-size: 20px; cursor: pointer; color: var(--muted); }

/* ---- welcome popup (same .veil/.modal family, sized up for its content) ----
   Distinct tinted background + stronger shadow/border than plain .modal — at this
   size it needs to read unmistakably as a floating overlay, not another page card. */
.modal-lg {
  max-width: 720px; max-height: calc(100vh - 60px); overflow-y: auto;
  /* warm accent tint, not blue — the page canvas itself already has a cool blue-ish
     wash (--bg + accent2 glow), so a blue-tinted popup nearly matched it and still
     read as "part of the page" instead of a distinct overlay. */
  background: linear-gradient(165deg, color-mix(in srgb, var(--accent) 16%, var(--paper)), var(--paper) 60%);
  border: 1px solid color-mix(in srgb, var(--accent) 38%, var(--line));
  box-shadow: 0 28px 70px -18px var(--shadow-lg), 0 4px 14px var(--shadow-sm);
}
.modal-lg .eyebrow { margin: 0 0 8px; }
.modal-lg h3 { font-size: 22px; }
.welcome-risk {
  font-size: 13px; color: var(--muted); background: color-mix(in srgb, var(--accent) 8%, transparent);
  border: 1px solid var(--line); border-radius: 8px; padding: 10px 12px; margin: 10px 0;
}
.welcome-features { display: flex; flex-direction: column; gap: 9px; margin: 16px 0; }
.welcome-features div { display: flex; gap: 10px; align-items: flex-start; font-size: 14px; color: var(--ink); }
.welcome-features span { flex: none; font-size: 17px; line-height: 1.4; }
.welcome-cats { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px 18px; margin: 18px 0 6px; }
.welcome-cat h4 { margin: 0 0 2px; font-size: 13.5px; position: relative; padding-inline-start: 14px; }
.welcome-cat h4::before {
  content: ""; position: absolute; inset-inline-start: 0; top: 3px; bottom: 3px; width: 4px;
  border-radius: 2px; background: linear-gradient(180deg, var(--accent), var(--accent2));
}
.welcome-cat p { margin: 0; font-size: 12.5px; color: var(--muted); padding-inline-start: 14px; }
.welcome-closing { margin: 16px 0 4px; font-size: 14px; color: var(--ink); }
.welcome-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 14px; flex-wrap: wrap; }
@media (max-width: 560px) { .welcome-cats { grid-template-columns: 1fr; } }

/* ---- cookie consent banner ---- */
.consent { position: fixed; left: 0; right: 0; bottom: 0; z-index: 50; background: var(--paper); border-top: 1px solid var(--line); box-shadow: 0 -2px 12px var(--shadow-sm); }
.consent.hidden { display: none; }
.consent-in { max-width: 1180px; margin: 0 auto; padding: 16px 18px; display: flex; gap: 16px; align-items: center; flex-wrap: wrap; }
.consent-in p { margin: 0; color: var(--muted); font-size: 13.5px; flex: 1 1 320px; }
.consent-actions { display: flex; gap: 10px; flex: none; }

/* ---- language picker (flag button + Z-A menu, toggled in site.js) ---- */
.lang { position: relative; }
.lang-btn { display: inline-flex; align-items: center; padding: 8px 10px; }
.lang svg.flag { width: 20px; height: 14px; border-radius: 3px; box-shadow: 0 0 0 1px var(--line); display: block; flex: none; }
.lang-menu {
  position: absolute; inset-inline-end: 0; top: calc(100% + 8px); z-index: 60;
  margin: 0; padding: 6px; list-style: none; min-width: 178px;
  background: var(--paper); border: 1px solid var(--line); border-radius: 10px;
  box-shadow: 0 1px 2px var(--shadow-sm), 0 14px 38px -14px var(--shadow-lg);
}
.lang-menu a { display: flex; align-items: center; gap: 10px; padding: 7px 10px; border-radius: 7px; color: var(--ink); text-decoration: none; font-size: 14px; white-space: nowrap; }
.lang-menu a:hover { background: var(--bg); }
.lang-menu a[aria-current="true"] { background: var(--bg); font-weight: 600; }

/* ===== CBCOM CAD Studio layout (2026-07-22, Fikret): big single-column sheet, top action
   bar with on-demand property popovers, a floating draggable tool palette, full screen ===== */
.cadstudio .cs-bar { margin: 2px 0 6px; }
.cs-actionbar { border-top: 1px solid var(--line); padding-top: 8px; }
.cs-actionbar [data-pop].active { background: color-mix(in srgb, var(--accent2) 16%, transparent); border-color: var(--accent2); }
.cs-inline { display: inline-flex; align-items: center; gap: 6px; margin: 0; }
.cs-inline select { width: auto; }
.cs-import { padding: 6px 12px; margin: 0; }

/* Snijlagen-eiland (2026-07-30). Alleen de vorm staat hier — de laagKLEUREN zijn
   gegevens die dxf-engine.js aanlevert en die JS op .lay-dot zet, dus er staat hier
   bewust geen enkele kleurwaarde. */
.lay-rows { display: flex; flex-direction: column; gap: 4px; margin: 8px 0; }
.lay-row { display: flex; align-items: center; gap: 6px; }
.lay-row.on { background: color-mix(in srgb, var(--accent2) 12%, transparent); border-radius: 6px; }
.lay-name { flex: 1 1 auto; display: flex; align-items: center; gap: 6px; min-width: 0; text-align: start;
            background: none; border: 0; padding: 4px 6px; cursor: pointer; color: inherit; font: inherit; border-radius: 6px; }
.lay-name:hover { background: color-mix(in srgb, var(--ink) 8%, transparent); }
.lay-row.on .lay-name { font-weight: 600; }
.lay-name .meta { font-size: .8em; }
.lay-dot { width: 12px; height: 12px; border-radius: 3px; border: 1px solid var(--line); flex: 0 0 auto; }
.lay-col { width: 96px; flex: 0 0 auto; }
.lay-eye { padding: 2px 6px; flex: 0 0 auto; }

/* Tool palette — its home is docked to the LEFT window edge, draggable by its head
   (Fikret 2026-07-23). All tools stacked vertically; the coordinate/size inputs pop
   out as a WIDE panel beside the palette so the numbers are readable. */
.cs-palette,
.cs-pal3 {
  position: fixed; top: 190px; inset-inline-start: 12px; z-index: 30; width: 154px;
  background: var(--paper); border: 1px solid var(--line); border-radius: 10px;
  box-shadow: 0 2px 6px var(--shadow-sm), 0 14px 34px -14px var(--shadow-lg);
  padding: 6px; user-select: none;
}
.cs-palette-head,
.cs-pal3-head {
  cursor: grab; font-weight: 600; font-size: .82em; text-align: center; padding: 4px 6px;
  margin: -6px -6px 6px; border-bottom: 1px solid var(--line); border-radius: 10px 10px 0 0;
  background: color-mix(in srgb, var(--accent2) 10%, var(--paper));
}
.cs-palette-head:active,
.cs-pal3-head:active { cursor: grabbing; }
.cs-pal3 > .cs-palette-tools,
.cs-palette-tools { display: grid; grid-template-columns: 1fr; gap: 4px; }   /* all tools under each other */
.cs-palette-tools .ghost { padding: 7px 9px; font-size: .86em; text-align: start; }
/* the 3D palette: two compact columns (Fikret 2026-07-28 — "kleinere iconen en
   meerdere tegels zodat alles binnen handbereik ligt") + a block of direct action
   tiles (booleans, group) under the drawing tools. Text stays on every tile —
   icon-only buttons are ruled out by the accessibility triple-encoding rule. */
.cs-pal3 { width: 208px; }
.cs-pal3 > .cs-palette-tools { grid-template-columns: 1fr 1fr; gap: 3px; }
.cs-pal3 > .cs-palette-tools .ghost { padding: 5px 6px; font-size: .78em; }
.cs-pal-acts,
.cs-pal3-acts {
  display: grid; grid-template-columns: 1fr 1fr; gap: 3px;
  border-top: 1px solid var(--line); margin-top: 6px; padding-top: 6px;
}
.cs-pal-acts .ghost,
.cs-pal3-acts .ghost { padding: 5px 6px; font-size: .78em; text-align: start; }
/* the coordinate/size flyout: sits just to the right of the palette, moves with it,
   only shown while a tool that needs input is active (setTool → .cs-fields-open) */
.cs-palette-fields {
  display: none;
  position: absolute; inset-inline-start: 100%; top: 0; margin-inline-start: 8px; width: 244px;
  background: var(--paper); border: 1px solid var(--line); border-radius: 10px;
  box-shadow: 0 2px 6px var(--shadow-sm), 0 16px 40px -14px var(--shadow-lg); padding: 10px 12px;
}
.cs-palette.cs-fields-open > .cs-palette-fields,
.cs-pal3.cs-fields-open > .cs-palette-fields { display: block; }
/* Deze veldstijlen gelden voor BEIDE plekken waar een veldgroep kan staan: de
   uitklapper naast het palet en het zwevende gereedschapsvenster dat hem leent. Zonder
   .cs-toolwin-body erbij zou een verhuisde groep zijn opmaak verliezen. */
.cs-palette-fields .fld,
.cs-toolwin-body .fld { display: block; width: 100%; font-size: .9em; color: var(--muted); margin-bottom: 9px; }
.cs-palette-fields .fld .unit-tag,
.cs-toolwin-body .fld .unit-tag { font-size: .82em; margin-inline-start: 4px; }
.cs-palette-fields .cs-xy,
.cs-toolwin-body .cs-xy { display: flex; gap: 6px; margin-top: 4px; }
/* Hoogte als MINIMUM, nooit als vaste maat. Een vaste 34px bovenop de globale
   padding van 9px liet maar 14px over voor een regel van 14px, en dan knipt de
   browser de letters af — precies wat Fikret op de keuzelijst "Teksttype" zag
   (2026-07-29). Elk veld hier zet daarom zijn eigen padding. */
.cs-palette-fields .fld input[type=number],
.cs-palette-fields .cs-xy input[type=number],
.cs-toolwin-body .fld input[type=number],
.cs-toolwin-body .cs-xy input[type=number] { flex: 1 1 0; min-width: 0; width: 100%; font-size: 15px; min-height: 34px; padding: 5px 8px; margin-top: 4px; }
.cs-palette-fields .cs-xy input[type=number],
.cs-toolwin-body .cs-xy input[type=number] { margin-top: 0; }
.cs-palette-fields .fld input[type=text],
.cs-toolwin-body .fld input[type=text] { width: 100%; font-size: 15px; min-height: 34px; padding: 5px 8px; margin-top: 4px; }
/* de 30px rechts houdt het pijltje van de keuzelijst vrij */
.cs-palette-fields select,
.cs-toolwin-body select { width: 100%; font-size: 14px; min-height: 34px; padding: 6px 30px 6px 8px; margin-top: 4px; }
/* De maat-keuzelijst (straal of diameter) IS het opschrift van zijn veld: hij staat waar
   een gewoon label staat en houdt dus alleen de breedte die zijn tekst nodig heeft. Zo
   lees je bij het intypen altijd wélke maat er in het vakje hoort. */
.cs-palette-fields select.cs-modesel,
.cs-toolwin-body select.cs-modesel { width: auto; max-width: 100%; min-height: 26px; padding: 2px 24px 2px 6px; margin-top: 0; font-size: .9em; }
.cs-palette-fields .full,
.cs-toolwin-body .full { width: 100%; text-align: center; }
.cs-palette-fields .meta,
.cs-toolwin-body .meta { font-size: .85em; }
/* Δ-knop bij het tweede punt (Fikret 2026-08-02, relatieve invoer): compact en op de
   bijschrift-regel, zodat hij de twee invoervelden nooit uit elkaar duwt. Bewust géén
   eigen kleurtje — .ghost.active toont al of hij aanstaat. */
.cs-relbtn { padding: 1px 7px; font-size: .95em; line-height: 1.25; margin-inline-start: 6px; vertical-align: middle; }
/* Afronden/sluiten van een lopende polylijn. Staat er alleen zolang er één loopt; JS zet
   display terug op leeg, dus de vorm hoort hier en niet in het style-attribuut. */
#dLnPolyRow { display: flex; gap: 6px; margin-top: 2px; }
#dLnPolyRow > button { flex: 1 1 0; min-width: 0; }

/* Het eigen venster van het gekozen tekengereedschap (Fikret 2026-07-31). Het LEENT de
   veldgroep hierboven, dus alle veldstijlen gelden er ook: één regel erbij in plaats van
   een tweede set die uit de pas kan lopen. */
.cs-toolwin {
  position: fixed; z-index: 34; width: 268px; max-width: calc(100vw - 16px);
  background: var(--paper); border: 1px solid var(--line); border-radius: 10px;
  box-shadow: 0 2px 6px var(--shadow-sm), 0 16px 40px -14px var(--shadow-lg); padding: 6px;
}
.cs-toolwin-head {
  display: flex; align-items: center; gap: 6px; cursor: grab; user-select: none;
  font-weight: 600; font-size: .86em; padding: 5px 6px; margin: -6px -6px 8px;
  border-bottom: 1px solid var(--line); border-radius: 10px 10px 0 0;
  background: color-mix(in srgb, var(--accent2) 10%, var(--paper));
}
.cs-toolwin-head:active { cursor: grabbing; }
.cs-toolwin-head > span:first-child { flex: 1; }
.cs-toolwin-head button { padding: 2px 7px; line-height: 1.1; }
.cs-toolwin-body { padding: 4px 6px 6px; max-height: min(62vh, 560px); overflow: auto; }

/* action popovers — opened under their button, positioned by cad-studio-ui.js */
.cs-pop {
  position: fixed; z-index: 35; width: 288px; max-width: calc(100vw - 16px);
  background: var(--paper); border: 1px solid var(--line); border-radius: 10px;
  box-shadow: 0 2px 6px var(--shadow-sm), 0 16px 40px -14px var(--shadow-lg); padding: 10px 12px;
  /* Kop vast, inhoud scrollend: een paneel dat hoger is dan het scherm wordt door
     openPop() geklemd, en dan moet de inhoud kunnen schuiven in plaats van onder de
     onderrand te verdwijnen (Fikret 2026-08-01, het vectoriseer-venster). */
  display: flex; flex-direction: column; max-height: calc(100vh - 16px);
}
/* En dan moet het verbergen hier hardop gezegd worden. Een eigen display-regel wint van
   de browserregel [hidden] { display: none }, dus zonder deze regel is p.hidden = true in
   closeAll() een lege handeling: het ✕ sluit niets, panelen stapelen op elkaar en liggen
   over het tekenblad (Fikret 2026-08-01). Zelfde les als bij het palet hieronder — wie
   de display-regel hierboven ooit aanpast, moet deze meenemen. */
.cs-pop[hidden] { display: none; }
/* Tekenblad: draadkruis, en een verplaats-kruis zodra je boven een vorm hangt die met
   een dubbelklik is vrijgegeven om te slepen (zie dragArmedId in dxf-editor.js). */
#dCanvas { cursor: crosshair; }
#dCanvas.kan-slepen { cursor: move; }
.cs-pop-head { display: flex; align-items: center; justify-content: space-between; font-weight: 600; margin-bottom: 8px; gap: 8px; flex: 0 0 auto; }
.cs-pop-body { overflow: auto; min-height: 0; }
/* En de actieknop van het vectoriseer-venster plakt onderin dat scrollvak: een lijst mag
   scrollen, een knop mag nooit verdwijnen. Alleen deze — het is het enige paneel dat
   hoger kan worden dan het scherm, en de kiesknop erboven hoort juist bovenaan te staan. */
#dTraceGo { position: sticky; bottom: 0; z-index: 1; }
.cs-pop-close { border: 0; background: none; cursor: pointer; color: inherit; font-size: 1.05em; line-height: 1; padding: 2px 6px; border-radius: 6px; }
.cs-pop-close:hover { background: color-mix(in srgb, var(--ink) 8%, transparent); }
.cs-pop select { width: auto; }

/* full screen — the whole studio fills the viewport, buttons stay on top */
body.cs-fullscreen #dStudio,
body.cs-fullscreen #d3Studio { position: fixed; inset: 0; z-index: 40; background: var(--bg); padding: 10px; margin: 0; overflow: auto; }
body.cs-fullscreen .cs-palette,
body.cs-fullscreen .cs-pal3 { z-index: 42; }
body.cs-fullscreen .cs-pop { z-index: 43; }
/* the palette is position:fixed, so the plain hidden attribute needs saying out loud */
.cs-palette[hidden],
.cs-pal3[hidden] { display: none; }
/* 2D ⇄ 3D switch, parked next to the palette so it is always reachable */
/* Hoort bij de bediening, niet als zwevend kaartje boven de pagina: vast gepind
   rechtsboven landde deze regel in de desktopapp pal op de paneelkolom (Fikret
   2026-07-29). cad-studio-ui.js hangt hem in de gereedschapsbalk van het gekozen
   werkvlak; margin-inline-start:auto duwt hem daar netjes naar het eind. */
.cs-modebar {
  display: inline-flex; align-items: center; gap: 6px; margin-inline-start: auto;
  background: var(--paper); border: 1px solid var(--line);
  border-radius: 10px; padding: 4px 6px;
}
.cs-modebar[hidden] { display: none; }
/* in 3D the drawing sheet fills its box itself — no letterboxing around the canvas */
#d3CanvasWrap { background: var(--paper); height: 62vh; min-height: 340px; }
/* full screen has to mean full screen: 62vh leaves a third of the window unused */
body.cs-fullscreen #d3CanvasWrap { height: calc(100vh - 220px); min-height: 260px; }

@media (max-width: 860px) {
  .cs-palette,
  .cs-pal3 { position: static; width: 100%; margin: 8px 0; inset-inline-start: auto; }
  .cs-palette-tools { grid-template-columns: repeat(5, 1fr); }
  /* on a phone the flyout can't float beside the palette — stack it in flow, full width */
  .cs-palette-fields { position: static; width: 100%; margin: 8px 0 0; }
}

/* Video Studio scrub-hover time bubble (2026-07-22, Fikret): shows h/m/s under the cursor */
.vs-scrubtip {
  position: fixed; z-index: 60; transform: translate(-50%, -135%);
  background: var(--ink); color: var(--paper); font: 600 11px var(--mono, ui-monospace, monospace);
  padding: 2px 6px; border-radius: 5px; pointer-events: none; white-space: nowrap;
  box-shadow: 0 2px 8px var(--shadow-sm);
}

/* ---- CBCOM Document Studio (2026-07-28) -----------------------------------
   The PDF viewer is a scrolling column of pages; each page carries the rendered
   canvas and a transparent annotation canvas on top. Everything is sized in CSS
   pixels while the canvases are backed at devicePixelRatio, so text stays crisp
   at every zoom level. */
#dsViewWrap {
  /* Starting point only — fitViewerHeight() in document-studio.js measures the real gap
     between this box and the bottom of the window and stretches it to fill. A document is
     read top to bottom, so every pixel of height is worth more here than in a studio that
     works on a wide timeline. */
  height: 72vh;
  overflow: auto;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 14px 0;
}
#dsPages { display: flex; flex-direction: column; align-items: center; gap: 14px; }
.ds-page {
  position: relative;
  background: #fff;
  box-shadow: var(--shadow-lg);
  flex: 0 0 auto;
}
.ds-page canvas { position: absolute; inset: 0; display: block; }
/* Afdrukvoorbeeld: de pagina's onder elkaar, scrollend binnen het venster zodat de
   afdrukknop eronder altijd bereikbaar blijft. */
.ds-prev { max-height: 60vh; overflow: auto; display: flex; flex-direction: column; gap: 10px; padding: 2px; }
.ds-prev figure { margin: 0; }
.ds-prev img { display: block; width: 100%; height: auto; border: 1px solid var(--line); background: #fff; }
.ds-prev figcaption { font-size: 12px; color: var(--muted); text-align: center; padding-top: 2px; }
/* Kleurvakjes in de opmaakbalk: even hoog als de knoppen ernaast, zodat de rij
   niet uit elkaar valt. Een kale <input type=color> is per motor anders groot. */
.ds-swatch { width: 34px; height: 30px; padding: 2px; border: 1px solid var(--line); border-radius: 8px; background: var(--paper); cursor: pointer; }
.ds-swatch::-webkit-color-swatch-wrapper { padding: 0; }
.ds-swatch::-webkit-color-swatch { border: 0; border-radius: 5px; }
.ds-pga { touch-action: none; }
#dsPages[data-mode="select"] .ds-page { cursor: default; }
#dsPages[data-mode="edit"] .ds-page,
#dsPages[data-mode="add"] .ds-page { cursor: text; }
#dsPages[data-mode="white"] .ds-page,
#dsPages[data-mode="redact"] .ds-page,
#dsPages[data-mode="hl"] .ds-page,
#dsPages[data-mode="ul"] .ds-page,
#dsPages[data-mode="st"] .ds-page,
#dsPages[data-mode="rect"] .ds-page,
#dsPages[data-mode="ell"] .ds-page,
#dsPages[data-mode="line"] .ds-page,
#dsPages[data-mode="arrow"] .ds-page { cursor: crosshair; }
#dsPages[data-mode="pen"] .ds-page { cursor: crosshair; }
#dsPages[data-mode="note"] .ds-page { cursor: copy; }
/* Handgereedschap. De cursor moet óók op de grijze rand naast het papier staan,
   dus op de hele stapel én op de pagina zelf — de pagina heeft een eigen regel en
   zou die van de ouder anders overschrijven. */
#dsPages[data-mode="pan"],
#dsPages[data-mode="pan"] .ds-page { cursor: grab; }
#dsPages.ds-panning,
#dsPages.ds-panning .ds-page { cursor: grabbing; }

/* Tabelknoppen: twee smalle getalvelden met een × ertussen, zodat "3 × 3" op één
   regel past en de opmaakbalk niet openbreekt. */
.ds-tblgrp input[type="number"] { width: 46px; padding: 4px 6px; }

/* Sjablonen en handtekeningen worden sinds 2026-07-31 door het gedeelde
   cbUserLib-paneel getekend; hier blijft alleen de plek waar dat paneel in hangt.
   Geen eigen hoogte of scroller: het paneel scrollt zelf al, en twee schuifbalken
   in elkaar is precies wat een lijst onbruikbaar maakt. */
.ds-tpl-list { margin-top: 6px; }

/* page thumbnails */
.ds-thumbs {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(92px, 1fr));
  gap: 8px;
  max-height: 260px;
  overflow-y: auto;
}
.ds-thumb {
  position: relative;
  display: block;
  padding: 3px;
  border: 2px solid var(--line);
  border-radius: 6px;
  background: var(--paper);
  cursor: pointer;
  line-height: 0;
}
.ds-thumb.on { border-color: var(--accent); }
.ds-thumb canvas { width: 100%; height: auto; background: #fff; }
.ds-thumb span {
  position: absolute; right: 4px; bottom: 3px;
  font: 600 10px/1.2 system-ui, sans-serif;
  background: var(--paper); color: var(--ink);
  padding: 0 4px; border-radius: 4px; line-height: 1.4;
}

/* the loose PDF tools column */
.ds-toollist { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.ds-toollist button { width: 100%; text-align: start; font-size: 12.5px; }

/* a tool window: floats, drags by its title bar, never needs the page to scroll */
.ds-tw {
  position: fixed;
  min-width: 320px;
  max-width: min(520px, 92vw);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: var(--shadow-lg);
}
.ds-tw-h {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; padding: 7px 8px 7px 12px;
  border-bottom: 1px solid var(--line);
  font-weight: 600; cursor: grab;
}
.ds-tw-h button { padding: 2px 8px; }
.ds-tw-b { padding: 12px; max-height: 66vh; overflow: auto; }
.ds-tw-b .fld { width: 100%; }
.ds-sign { border: 1px dashed var(--line); border-radius: 8px; background: #fff; touch-action: none; width: 100%; height: auto; }
/* De bewaarde handtekeningen worden door het gedeelde cbUserLib-paneel getekend
   (2026-07-31) — de eigen strip-stijlen hieronder zijn daarmee vervallen. */

/* "now click on the page" note — sticky INSIDE the scrolling viewer, so it stays
   in sight however far the document is scrolled (the status line is off-screen
   in the desktop app, which read as "photo insert does nothing") */
.ds-placenote {
  position: sticky; top: 6px; z-index: 6;
  margin: 6px auto; width: max-content; max-width: 92%;
  background: var(--accent); color: #fff;
  padding: 6px 12px; border-radius: 8px;
  font-size: 13px; box-shadow: var(--shadow-sm);
  pointer-events: none;
}
.ds-placing .ds-page { cursor: crosshair; }

/* a <label> file field has no :disabled — the class mirrors it */
label.ghost.disabled { opacity: .45; pointer-events: none; }

/* inline text editor over the page */
.ds-inline {
  position: fixed; z-index: 60;
  display: flex; gap: 6px; align-items: flex-start;
  background: var(--paper);
  border: 1px solid var(--accent);
  border-radius: 8px; padding: 8px;
  box-shadow: var(--shadow-lg);
}
.ds-inline textarea { min-width: 220px; min-height: 44px; resize: both; }

/* the document editor (Word / Markdown / text side) */
.ds-doc {
  height: 72vh; overflow: auto;
  background: #fff; color: #111;
  border: 1px solid var(--line); border-radius: 10px;
  padding: 36px 44px;
  font: 15px/1.6 Georgia, "Times New Roman", serif;
}
.ds-doc:focus { outline: 2px solid var(--accent2); outline-offset: -2px; }
.ds-doc h1 { font-size: 26px; margin: 0 0 12px; }
.ds-doc h2 { font-size: 21px; margin: 18px 0 8px; }
.ds-doc h3 { font-size: 17px; margin: 14px 0 6px; }
.ds-doc p { margin: 0 0 10px; }
.ds-doc blockquote { margin: 10px 0; padding-inline-start: 14px; border-inline-start: 3px solid #ccc; color: #555; }
.ds-doc pre { background: #f4f4f4; padding: 10px; border-radius: 6px; overflow: auto; font: 13px/1.5 Consolas, monospace; }
.ds-doc table { border-collapse: collapse; width: 100%; font: 13px/1.4 system-ui, sans-serif; }
.ds-doc th, .ds-doc td { border: 1px solid #ccc; padding: 4px 7px; min-width: 60px; }
.ds-doc th { background: #f0f0f0; font-weight: 600; }

/* keep the export buttons put — a scrolling list is fine, a vanishing button is not */
.ds-out-actions { position: sticky; top: 0; background: var(--paper); z-index: 1; padding-bottom: 4px; }

@media (max-width: 900px) {
  #dsViewWrap, .ds-doc { height: 60vh; }
  .ds-toollist { grid-template-columns: 1fr; }
  .ds-doc { padding: 20px 18px; }
}

/* In de DESKTOPAPP bepaalt de schil de hoogte: #dsWorkspace is daar het werkvlak
   en vult de stage (.cbw-work krijgt height:100%). De vaste 72vh hierboven — en
   de hoogte die fitViewerHeight anders zou meten — werkt daar tegenin: het
   leesvenster bleef op een verse start op 76% van de beschikbare hoogte steken.
   Alleen in de app (html.cb-app-layout zet de schil zelf); de website houdt zijn
   vh-hoogte, want daar scrollt de pagina wél. */
html.cb-app-layout #dsWorkspace { display: flex; flex-direction: column; min-height: 0; }
html.cb-app-layout #dsWorkspace > #dsViewWrap,
html.cb-app-layout #dsWorkspace > #dsDocWrap {
  flex: 1 1 auto;
  min-height: 0;
  height: auto !important;
}
/* De bewerker is zelf ook een kolom: opmaakbalk vast bovenaan, tekstvlak vult
   de rest. Zonder dit houdt .ds-doc zijn eigen 72vh binnen een doos die al
   precies past, en scrollt de bewerker binnen de bewerker. */
html.cb-app-layout #dsDocWrap { display: flex; flex-direction: column; }
html.cb-app-layout #dsDocWrap > .ds-doc { flex: 1 1 auto; min-height: 0; height: auto !important; }

.net-mark { font-size: .82em; opacity: .55; margin-inline-start: 2px; }

/* CAD Studio: de knoppenband bovenaan was vier rijen hoog (Fikret 2026-07-29,
   "wel 5-6 cm"). Alles behalve de transportrij zit nu in eilanden naast het
   tekenblad, zoals de andere vier studio's. Onder 1000px stapelt het. */
.cs-work { display: flex; gap: 12px; align-items: flex-start; }
.cs-work > .cs-main { flex: 1 1 0; min-width: 0; }
.cs-work > .mx-islands { flex: 0 0 300px; max-width: 300px; }
/* In de desktopapp verhuist de schil de eilanden naar zijn eigen dok. De kolom
   waar ze uit komen bleef dan als leeg vak van 300px staan en pikte een derde
   van het tekenblad in (gemeten 2026-07-30: 757 -> 445 px breed). Op de website
   staan de eilanden hier wél, dus daar verandert deze regel niets. */
.cs-work > .mx-islands:not(:has(.isl)) { display: none; }
@media (max-width: 1000px) {
  .cs-work { flex-direction: column; }
  .cs-work > .mx-islands { flex: 1 1 auto; max-width: none; width: 100%; }
}
/* Het 3D-tekenblad vult de hoogte van het werkvlak. In de app zet de schil er
   height:auto !important op en laat hij het met flex groeien — dat werkt alleen
   als de kolom eronder zelf een flexkolom van volle hoogte is. Zonder deze drie
   regels viel het blad terug op zijn min-height (340px) en bleef er onderaan een
   groot leeg vlak staan. Alleen in 3D: de 2D-indeling blijft zoals hij is.

   Waarom height:100% MÉT min-height en niet align-self:stretch — dat laatste is
   geprobeerd en gaf op de website een blad van 1691px hoog, want daar rekt stretch
   de kolom op tot de hoogte van de eilanden (gemeten). Nu: in de app heeft de
   ouder een vaste hoogte, dus 100% vult het werkvlak; op de website is die hoogte
   onbepaald, valt 100% terug op auto, en houdt de min-height het blad op 62vh. */
body.cs-mode-3d #d3Studio > .cs-work { flex: 1 1 auto; min-height: 0; }
body.cs-mode-3d .cs-work > .cs-main { display: flex; flex-direction: column; height: 100%; min-height: 62vh; }
body.cs-mode-3d .cs-work > .cs-main > #d3CanvasWrap { flex: 1 1 auto; min-height: 340px; }
