/* Kante v1 — https://github.com/shrippen/shrippen.github.io */
/*
 * Kante — CSS custom properties (web). Apps: qml/Kante, same values via tokens/palette.json
 * https://github.com/shrippen/shrippen.github.io
 *
 * Gruvbox-inspired, warm, dark-first palette.
 * Copy this block into your landing page <style> or import as a stylesheet.
 */

:root {
  /* ── Backgrounds ── */
  --bg-void:  #141312;   /* landing-page ground, darker than bg-hard */
  --bg-hard:  #1d2021;   /* deepest: hero gradient, code blocks */
  --bg0:      #282828;   /* page / widget background */
  --bg-panel: #2a2826;   /* landing-page cards and panels */
  --bg1:      #3c3836;   /* cards, elevated surfaces */
  --bg2:      #504945;   /* borders, dividers */

  /* ── Foregrounds ── */
  --fg0:      #fbf1c7;   /* primary heading (sparingly) */
  --fg1:      #ebdbb2;   /* body text */
  --fg2:      #d5c4a1;   /* secondary text */
  --fg3:      #a89984;   /* placeholder, disabled, footer */

  /* ── Brand accent ── */
  --accent:   #e8dcc4;   /* warm cream — icon fills, version badges */

  /* ── Semantic colors (Gruvbox bright) ── */
  --blue:     #83a598;   /* links, primary action */
  --blue-hover: #6d9181; /* primary button hover (~10% darker) */
  --aqua:     #8ec07c;   /* success, confirm */
  --green:    #b8bb26;   /* positive diff, badges */
  --yellow:   #fabd2f;   /* warning, attention */
  --orange:   #fe8019;   /* active, highlight */
  --red:      #fb4934;   /* error, destructive */
  --purple:   #d3869b;   /* tags, categories */
  --cyan:     #5ccfc4;   /* technical layer: focus, links, data, brackets. Lines and text, never large fills */
  --cyan-tint: #1e2b2a;  /* ground of a selected row or a focused field */
  --yellow-hi: #fdc94a;  /* primary hover (one step lighter) */
  --red-text: #ff7d6b;   /* red as small text: 4.5:1 on every dark ground, bg1 included */
  --yellow-lo: #e5a823;  /* primary pressed */

  /* ── Semantic colors (Gruvbox neutral — for quieter contexts) ── */
  --blue-n:   #458588;
  --aqua-n:   #689d6a;
  --green-n:  #98971a;
  --yellow-n: #d79921;
  --orange-n: #d65d0e;
  --red-n:    #cc241d;
  --purple-n: #b16286;
  --cyan-n:   #3f9a94;   /* quiet lines only (4.4:1 on cards) */

  /* ── Roles (follow the theme; see Light theme below) ── */
  --field:    var(--bg-hard); /* input fields, nested surfaces */
  --score:    var(--yellow);  /* scores, points, "how good is it" */
  --hl:       var(--cyan);    /* current selection (selected tile, active row) */
  --focus:    var(--cyan);    /* focus ring, everywhere */
  --link:     var(--cyan);    /* links in running text */
  --info:     var(--cyan);    /* info callouts and toasts, third feature tier */
  --warn:     var(--orange);  /* warnings: callout, banner, middle tier of states */
  --danger:   var(--red);     /* errors, destructive actions */
  --danger-text: var(--red-text); /* error text, critical labels and counts (not fills) */
  --on-state: var(--bg-void); /* text on a filled state colour (danger button, counters) */
  --scrim:    rgba(20,19,18,.62); /* dimmed area behind dialogs and outside a crop */
  --primary:  var(--yellow);  /* primary action, pressed segment, switch on, focus ring */
  --on-primary: var(--bg-void); /* text on --primary */
  --map-marker: var(--focus);   /* pins on a map (QML mapMarkerColor) */
  --map-route:  var(--primary); /* a route or track on a map (QML mapRouteColor) */
  --entity-fallback: var(--fg3); /* an entity without a colour of its own (QML entityFallbackColor) */

  /* ── Tints: translucent steps of the theme colours for hover, drop targets, selection, outlines ── */
  --tint-1:    color-mix(in srgb, var(--fg1) 8%, transparent);
  --tint-2:    color-mix(in srgb, var(--fg1) 16%, transparent);
  --tint-hl:   color-mix(in srgb, var(--cyan) 12%, transparent);
  --tint-hl-2: color-mix(in srgb, var(--cyan) 25%, transparent);
  --tint-warn: color-mix(in srgb, var(--orange) 14%, transparent);

  /* ── Data palette: series colours of charts, in this order (red stays danger) ── */
  --d1: var(--cyan);
  --d2: var(--yellow);
  --d3: var(--purple);
  --d4: var(--aqua);
  --d5: var(--orange);
  --d6: var(--fg3);

  /* ── Paper: stickers and brand chips (cream label, dark ink) ── */
  --paper:    var(--accent);
  --on-paper: var(--bg-void);

  /* ── Layout ── */
  --radius:   12px;
  --max-w:    860px;
  --max-w-wide: 1280px;  /* landing hero and feature rows */
  --gutter:   clamp(1rem, 5.6vw, 4.5rem);
  --chamfer:  16px;      /* top-right corner cut on boxes (surfaces) */
  --cut-m:    10px;      /* buttons, tiles, tabs, menus */
  --cut-s:    6px;       /* small buttons, stickers */
  --h-s:      32px;      /* control heights: small, medium, large */
  --h-m:      40px;
  --h-l:      48px;
  --h-xs:     24px;      /* dense parts below the control heights: chips, pills, stickers, inline buttons (touch: --h-s) */
  --h-mark:   20px;      /* counters and markers: .count, hint counts, the help "?" */
  --title-s:  1.1rem;    /* titles of cards, rows, tiles and bars (Rajdhani, uppercase) */
  --title-m:  1.4rem;    /* titles of blocks, sheets, dialogs and the login card */
  --title-l:  clamp(1.8rem, 4.2vw, 2.5rem); /* the title of an app page */
  --title-track: .04em;  /* letter spacing of --title-s and --title-m */

  /* ── Motion (only under prefers-reduced-motion: no-preference) ── */
  --dur-fast: 120ms;     /* colour and border changes */
  --dur:      200ms;     /* cut grows, lift, slide */
  --dur-slow: 450ms;     /* entrances: bar, scan, cascade */
  --ease-out: cubic-bezier(.2,.8,.2,1);
  --ease-snap: cubic-bezier(.3,1.5,.5,1); /* mechanical snap with a small overshoot */

  /* ── Typography ── */
  --font-heading: 'Rajdhani', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
                  Oxygen, Ubuntu, Cantarell, sans-serif;
  --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
               Ubuntu, Cantarell, sans-serif;
  --font-mono: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', Consolas, monospace;
  --font-control: var(--font-heading); /* buttons; Kante Gold keeps Rajdhani here while titles turn serif */
}

/*
 * Light theme ("Leinen") — opt-in via <html data-theme="light">.
 * Token names describe ROLES, not lightness: --bg-void is still the page
 * ground, --bg-panel the cards, --bg2 the borders, --fg1 the body text.
 * Landing pages stay dark-first; apps that need a light mode use this.
 * Semantic colors are the darkened counterparts so every text pair reaches
 * WCAG AA on the ground and on cards.
 */
:root[data-theme="light"] {
  color-scheme: light;

  /* ── Backgrounds ── */
  --bg-void:  #f0e9d6;   /* page ground: linen, between too-yellow #fbf1c7 and too-bright #f5f1e8 */
  --bg-hard:  #e6dec6;   /* sunk areas: code, progress tracks */
  --bg0:      #f0e9d6;
  --bg-panel: #f7f2e4;   /* cards and panels */
  --bg1:      #fbf8ee;   /* fields, elevated surfaces */
  --bg2:      #d3c8ac;   /* borders, dividers */

  /* ── Foregrounds ── */
  --fg0:      #282828;
  --fg1:      #3c3836;
  --fg2:      #665c54;
  --fg3:      #6a5f52;

  /* ── Brand accent ── */
  --accent:   #3c3836;   /* icon fill on light: dark square, yellow marks */

  /* ── Semantic colors (darkened for light grounds) ── */
  --blue:     #076678;
  --blue-hover: #05505f;
  --aqua:     #3a6e4e;
  --green:    #4f5d0a;
  --yellow:   #8a5a00;
  --orange:   #af3a03;
  --red:      #9d0006;
  --purple:   #8f3f71;
  --cyan:     #0f6b66;   /* 5.2:1 on the ground */
  --cyan-tint: #d9ebe4;
  --red-text: #9d0006;

  --field:    var(--bg1);
  --scrim:    rgba(40,40,40,.5);
  --primary:  #fabd2f;   /* yellow fill with ink, as in the dark theme (not ochre with brown text) */
  --on-primary: #141312;
  --yellow-hi: #fcc845;
  --yellow-lo: #e5a823;
  --on-state: #fbf8ee;
}

/*
 * Kante Light (apps) — opt-in via <html data-kante="light">.
 * Kante shapes on the platform look: colors are Breeze and follow the
 * system's light/dark setting (prefers-color-scheme), like Kirigami.Theme
 * does for Qt apps. Controls keep a small radius and the system font;
 * css/components.css "Kante Light" adds the shape and type rules.
 * Semantic colors are the Breeze inks (readable as text on the ground).
 */
:root[data-kante="light"] {
  color-scheme: light;

  --bg-void:  #eff0f1;   /* window ground */
  --bg-hard:  #e3e5e7;   /* sunk areas, tracks */
  --bg0:      #eff0f1;
  --bg-panel: #fcfcfc;   /* cards, panels (view) */
  --bg1:      #fcfcfc;   /* fields */
  --bg2:      #c9ced2;   /* borders */

  --fg0:      #232629;
  --fg1:      #232629;
  --fg2:      #4d545b;
  --fg3:      #646e78;

  --accent:   #232629;

  --blue:     #1d6fa5;
  --blue-hover: #155a87;
  --aqua:     #1e8449;
  --green:    #1e8449;
  --yellow:   #a84f00;   /* "check" tier: Breeze neutral, darkened */
  --orange:   #a84f00;
  --red:      #bf2e3e;
  --purple:   #8e44ad;

  --field:    var(--bg1);
  --score:    var(--blue);
  --hl:       #3daee9;   /* Breeze highlight: selection, focus */
  --scrim:    rgba(35,38,41,.5);
  --primary:  #3daee9;
  --on-primary: #ffffff;
  --cyan:     #1d6fa5;   /* Kante Light has no cyan: the platform's link and focus colours */
  --cyan-n:   #1d6fa5;
  --cyan-tint: #e3eef6;
  --red-text: var(--red);
  --yellow-hi: #3daee9;
  --yellow-lo: #2e9bd4;
  --on-state: #ffffff;
}

@media (prefers-color-scheme: dark) {
  :root[data-kante="light"] {
    color-scheme: dark;

    --bg-void:  #202326;
    --bg-hard:  #1b1e20;
    --bg0:      #202326;
    --bg-panel: #292c30;
    --bg1:      #1b1e20;
    --bg2:      #41464b;

    --fg0:      #ffffff;
    --fg1:      #fcfcfc;
    --fg2:      #d1d5d9;
    --fg3:      #a1a9b1;

    --accent:   #fcfcfc;

    --blue:     #3daee9;
    --blue-hover: #2e9bd4;
    --aqua:     #3ec57a;
    --green:    #3ec57a;
    --yellow:   #f69a3d;
    --orange:   #f69a3d;
    --red:      #ed5a6a;
    --purple:   #b56fd0;

    --scrim:    rgba(0,0,0,.55);
    --cyan:     #3daee9;
    --cyan-n:   #3daee9;
    --cyan-tint: #1e3342;
    --red-text: var(--red);
    --yellow-hi: #3daee9;
    --yellow-lo: #2e9bd4;
    --on-state: #202326;
  }
}

/*
 * Kante Gold — opt-in via <html data-kante="gold">. Only Kintsugi uses it (see AGENT-RULE.md).
 * The noble variant: the same components and sizes on urushi lacquer, paper text and gold.
 * Every cut edge is gilded, bars are 2 px, titles and figures are Spectral, motion glides.
 * Dark only. css/components.css "Kante Gold" adds the shape, type and motion rules.
 * Patina (verdigris) takes cyan's roles: focus, links, info.
 */
:root[data-kante="gold"] {
  color-scheme: dark;

  /* ── Backgrounds: lacquer ── */
  --bg-void:  #14110f;   /* urushi: page ground */
  --bg-hard:  #0f0d0b;   /* sunk areas, fields, tracks */
  --bg0:      #1c1815;
  --bg-panel: #1c1815;   /* lacquer: cards and panels */
  --bg1:      #262019;   /* elevated, hover */
  --bg2:      #3b3229;   /* borders, dividers */

  /* ── Foregrounds: paper ── */
  --fg0:      #faf5e9;
  --fg1:      #efe8d8;
  --fg2:      #cdc2ae;
  --fg3:      #a39885;   /* ash: 6.6:1 on the ground */

  /* ── Brand accent: pale gold ── */
  --accent:   #e8d4a6;

  /* ── Semantic colors: metals and pigments ── */
  --blue:     #8aa1ab;   /* slate */
  --blue-hover: #77909a;
  --aqua:     #97ad7a;   /* jade: success */
  --green:    #a9b26b;
  --yellow:   #d4a640;   /* gold: primary, lines, score */
  --orange:   #d08a55;   /* copper: warning */
  --red:      #d0705a;   /* cinnabar: error */
  --purple:   #c497a8;   /* ume: tags */
  --cyan:     #8fb8aa;   /* patina: focus, links, info */
  --cyan-n:   #6f9488;
  --cyan-tint: #1b2321;
  --yellow-hi: #e0b65a;
  --yellow-lo: #b88f2f;
  --red-text: #e48b74;

  --scrim:    rgba(15,13,11,.72);
  --d1: var(--yellow);
  --d2: var(--cyan);

  /* ── Gold only ── */
  --gold-line: color-mix(in srgb, var(--yellow) 32%, transparent); /* hairlines, frames */
  --gild:     1.6px;     /* the gold line on every cut edge */
  --bar:      2px;       /* state and tier bars (Kante: 4 px) */

  /* ── Motion: glides, no overshoot ── */
  --dur-fast: 160ms;
  --dur:      280ms;
  --dur-slow: 700ms;
  --ease-snap: cubic-bezier(.2,.8,.2,1);

  /* ── Typography: serif titles and figures, Rajdhani stays on the controls ── */
  --font-heading: 'Spectral', Georgia, 'Times New Roman', serif;
  --font-control: 'Rajdhani', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
                  Oxygen, Ubuntu, Cantarell, sans-serif;
}
/* ── Base ── */
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
body{background:var(--bg-void);color:var(--fg1);font-family:var(--font-sans);line-height:1.6;
  -webkit-font-smoothing:antialiased}
body{overflow-x:clip}
a{color:var(--link);text-decoration:none}
a:hover{text-decoration:underline}
code{font-family:var(--font-mono);font-size:.85em;color:var(--fg2)}
/* The hidden attribute wins over every Kante display rule (.tile-tools, .bulk-bar, .editbar, …) */

/* ── Language: paired elements, e.g. <p lang="en">…</p><p lang="de">…</p>.
   <html lang> is "en" by default; shrippen.js switches it. ── */
html[lang="en"] [lang="de"],html[lang="de"] [lang="en"]{display:none!important}
/* Registered so the cut can animate (A01, A19). */
/* [hidden] wins over every display rule below; here, not in base.css, so apps without the reset get it too */
[hidden]{display:none!important}
@property --chamfer{syntax:"<length>";inherits:true;initial-value:16px}
@property --c1{syntax:"<length>";inherits:false;initial-value:0px}
@property --c2{syntax:"<length>";inherits:false;initial-value:0px}
@property --run{syntax:"<angle>";inherits:false;initial-value:0deg}
/* Focus brackets (A03): four cyan corners, drawn as backgrounds so they work inside a cut box. */
:root{--brk:linear-gradient(var(--focus),var(--focus)) top left/12px 2px no-repeat,linear-gradient(var(--focus),var(--focus)) top left/2px 12px no-repeat,
  linear-gradient(var(--focus),var(--focus)) top right/12px 2px no-repeat,linear-gradient(var(--focus),var(--focus)) top right/2px 12px no-repeat,
  linear-gradient(var(--focus),var(--focus)) bottom left/12px 2px no-repeat,linear-gradient(var(--focus),var(--focus)) bottom left/2px 12px no-repeat,
  linear-gradient(var(--focus),var(--focus)) bottom right/12px 2px no-repeat,linear-gradient(var(--focus),var(--focus)) bottom right/2px 12px no-repeat}

/* Boxes share one shape: only the top-right corner is cut. */
.ch,.install-card,.hero-shot,.shots img,.feat,.callout,.codeblock,.table-wrap{
  clip-path:polygon(0 0,calc(100% - var(--chamfer)) 0,100% var(--chamfer),100% 100%,0 100%)}

/* ── Nav: sticky; the project name fades in once the hero has left the viewport ── */
.nav{position:sticky;top:0;z-index:10;background:color-mix(in srgb,var(--bg-void) 92%,transparent);backdrop-filter:blur(8px);
  border-bottom:1px solid var(--bg1)}
.nav-inner{display:flex;align-items:center;gap:1.5rem;max-width:var(--max-w-wide);margin:0 auto;
  padding:.6rem var(--gutter);min-height:56px}
.nav-brand{display:flex;align-items:center;gap:.6rem;font-family:var(--font-heading);font-weight:700;
  font-size:1.2rem;letter-spacing:.2em;text-transform:uppercase;color:var(--accent);
  opacity:0;transform:translateY(4px);pointer-events:none;
  transition:opacity .35s ease,transform .35s ease}
.nav-brand:hover{text-decoration:none}
.nav-brand img{width:24px;height:24px}
.nav-brand::before{content:"";width:6px;height:18px;background:var(--yellow);transform:scaleY(0);transform-origin:bottom}
.nav.brand-on .nav-brand::before,html:not(.js) .nav-brand::before{transform:none}
/* Scroll meter (A20): a cyan line under the nav; shrippen.js sets --scroll (0–1) */
.nav-meter{position:absolute;left:0;bottom:-1px;height:2px;width:calc(var(--scroll,0) * 100%);background:var(--cyan);pointer-events:none}
.nav.brand-on .nav-brand,html:not(.js) .nav-brand{opacity:1;transform:none;pointer-events:auto}
.nav-links{display:flex;align-items:center;gap:1.8rem;margin-left:auto}
.nav-links a{font-family:var(--font-mono);font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;color:var(--fg3)}
.nav-links a:hover{color:var(--fg0);text-decoration:none}
.nav-links a.nav-hl{color:var(--yellow)}
.nav-inner.is-wrap{flex-wrap:wrap;gap:.5rem 1rem}
.nav-inner.is-wrap .nav-links{flex-wrap:wrap;gap:.5rem 1.1rem;margin-left:0}
.nav-inner.is-wrap .nav-tools{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem .8rem;margin-left:auto}
.lang{display:flex;border:1px solid var(--bg2)}
.lang button{background:none;border:0;padding:.3rem .6rem;font-family:var(--font-mono);font-size:.72rem;
  letter-spacing:.1em;color:var(--fg3);cursor:pointer}
.lang button:hover{color:var(--fg0)}
.lang button[aria-pressed="true"]{background:var(--primary);color:var(--on-primary)}
.nav a:focus-visible,.lang button:focus-visible,.copy-btn:focus-visible{outline:2px solid var(--focus);outline-offset:2px}

/* ── Hero: name and tagline left, install box and screenshot right ── */
.hero{max-width:var(--max-w-wide);margin:0 auto;padding:clamp(2rem,5vw,3.5rem) var(--gutter) 0;
  display:grid;grid-template-columns:minmax(0,1.25fr) minmax(0,1fr);gap:3rem;align-items:end;
  position:relative}
.hero>*{position:relative;z-index:1}
/* The watermark bleeds right; clip it at the hero so the page never scrolls sideways. */
.hero:has(>.hero-wm){overflow-x:clip}
/* Watermark: the monochrome logo, huge and faint behind the hero. Scrolls with the page (not fixed).
   It may bleed below a short hero; the content after the hero (main, footer) paints above it. */
main,.foot{position:relative;z-index:1}
.hero>.hero-wm{position:absolute;z-index:0;right:-10rem;top:-2rem;width:min(58vw,55rem);height:auto;
  opacity:.07;pointer-events:none;user-select:none}
.hero-main{display:flex;flex-direction:column;gap:1.4rem}
.hero h1{font-family:var(--font-heading);font-weight:700;text-transform:uppercase;color:var(--fg0);
  font-size:var(--title-size,clamp(4.2rem,16.4vw,13.1rem));line-height:.82;letter-spacing:-.01em}
.hero h1 br.split{display:inline}
.tagline{font-size:clamp(1rem,2.5vw,1.25rem);color:var(--fg2);max-width:28em}
.hero-side{display:flex;flex-direction:column;gap:1.4rem;padding-bottom:.8rem}

/* ── Install box (yellow) ── */
.install-card{--chamfer:16px;clip-path:polygon(0 0,calc(100% - var(--chamfer)) 0,100% var(--chamfer),100% 100%,var(--chamfer) 100%,0 calc(100% - var(--chamfer)));background:var(--yellow);color:var(--bg-void);padding:1.9rem 1.9rem 2rem;display:flex;flex-direction:column;gap:1rem}
.install-card label{font-family:var(--font-heading);font-weight:700;font-size:1rem;letter-spacing:.18em;text-transform:uppercase}
.cmd-row{display:flex;gap:.5rem;align-items:stretch}
.cmd-box{flex:1;background:var(--bg-void);color:var(--yellow);padding:.85rem 1rem;font-family:var(--font-mono);
  font-size:.85rem;word-break:break-all;line-height:1.45;display:flex;align-items:center}
.copy-btn{background:var(--bg-void);color:var(--fg1);border:2px solid var(--bg-void);padding:.55rem .7rem;cursor:pointer;
  display:flex;align-items:center;justify-content:center;transition:color .15s,border-color .15s}
.copy-btn:hover{color:var(--fg0)}
.copy-btn.copied{border-color:var(--aqua);color:var(--aqua)}
.install-note{font-size:.8rem;line-height:1.5}
.install-note code{color:inherit}
.install-card a:not(.btn){color:inherit;text-decoration:underline}

/* ── Buttons: one height scale, top-right cut; primary and danger also cut bottom-left.
   Hover opens the cut (A01), press sets the button 1px in. clip-path would cut an outline,
   so focus is an inset ring and outlined buttons draw their diagonal as a background. ── */
.install-links{display:flex;flex-wrap:wrap;gap:.7rem}
.btn{--cut:var(--cut-m);--grow:6px;--c1:var(--cut);--c2:0px;position:relative;display:inline-flex;align-items:center;justify-content:center;gap:.5rem;
  min-height:var(--h-m);padding:0 1.35rem;border:0;cursor:pointer;background-color:transparent;color:inherit;white-space:nowrap;
  font-family:var(--font-control);font-weight:700;font-size:1rem;letter-spacing:.14em;text-transform:uppercase;text-decoration:none;
  clip-path:polygon(0 0,calc(100% - var(--c1)) 0,100% var(--c1),100% 100%,var(--c2) 100%,0 calc(100% - var(--c2)))}
.btn:hover{text-decoration:none}
.btn svg{width:18px;height:18px;flex-shrink:0;fill:none;stroke:currentColor}
.btn-sm{--cut:var(--cut-s);--grow:4px;min-height:var(--h-s);padding-inline:.9rem;font-size:.86rem;letter-spacing:.12em}
.btn-sm svg{width:15px;height:15px}
.btn-lg{--cut:12px;--grow:8px;min-height:var(--h-l);padding-inline:1.8rem;font-size:1.15rem;letter-spacing:.16em}
.btn-icon{padding-inline:0;width:var(--h-m)}.btn-sm.btn-icon{width:var(--h-s)}.btn-lg.btn-icon{width:var(--h-l)}
.btn:hover{--c1:calc(var(--cut) + var(--grow))}
.btn:active{transform:translate(1px,1px)}
.btn:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--focus),inset 0 0 0 4px var(--bg-void)}
.install-card .btn:focus-visible,.ground-yellow .btn:focus-visible{box-shadow:inset 0 0 0 2px var(--bg-void),inset 0 0 0 4px var(--yellow)}
/* filled with the double cut */
.btn-primary,.btn-accent,.btn-danger{--c2:var(--cut)}
.btn-primary:hover,.btn-accent:hover,.btn-danger:hover{--c2:calc(var(--cut) + var(--grow))}
/* outlined: border plus the drawn diagonal */
.btn-outline,.btn-ghost,.btn-data{--bw:2px;border:var(--bw) solid var(--bc);background-origin:border-box;background-repeat:no-repeat;background-position:top right;
  background-size:var(--c1) var(--c1);background-image:linear-gradient(to bottom left,transparent 50%,var(--bc) 50%,var(--bc) calc(50% + var(--bw)),transparent calc(50% + var(--bw)))}
/* inside the yellow box */
.btn-primary{background-color:var(--bg-void);color:var(--fg0)}
.btn-primary:hover{background-color:var(--bg-hard)}
.btn-ghost{--bc:var(--bg-void);color:var(--bg-void)}
.btn-ghost:hover{background-color:rgba(20,19,18,.1)}
/* on the page */
.btn-accent{background-color:var(--primary);color:var(--on-primary)}
.btn-accent:hover{background-color:var(--yellow-hi)}
.btn-accent:active{background-color:var(--yellow-lo)}
.btn-outline{--bc:var(--fg3);color:var(--fg1)}
.btn-outline:hover{--bc:var(--fg1);background-color:var(--bg1)}
.btn-danger{background-color:var(--danger);color:var(--on-state)}
.btn-danger:hover{filter:brightness(1.12)}
.btn-data{--bw:1px;--bc:var(--cyan-n);color:var(--cyan);font-family:var(--font-mono);font-weight:500;font-size:.78rem;letter-spacing:.12em}
.btn-data:hover{--bc:var(--cyan);background-color:var(--cyan-tint)}
.btn-quiet{--cut:0px;--grow:0px;padding-inline:.6rem;color:var(--fg2);font-family:var(--font-mono);font-weight:500;font-size:.78rem;letter-spacing:.12em}
.btn-quiet:hover{color:var(--fg0);background-color:var(--bg1)}
.btn:disabled,.btn[aria-disabled="true"]{--bc:var(--bg2);background-color:var(--bg1);color:var(--fg3);cursor:not-allowed;transform:none;filter:none}
.btn-outline:disabled,.btn-data:disabled,.btn-quiet:disabled{background-color:transparent}
/* busy (A08): marching hazard stripes in the fill */
.btn.is-busy{cursor:progress;background-image:repeating-linear-gradient(-45deg,var(--primary) 0 10px,var(--yellow-lo) 10px 20px);background-size:28.28px 28.28px}
.btn-outline.is-busy{background-image:repeating-linear-gradient(-45deg,transparent 0 10px,var(--bg1) 10px 20px)}
.btn-group{display:inline-flex;flex-wrap:wrap}
.btn-group .btn{--cut:0px;--grow:0px}.btn-group .btn:last-child{--cut:var(--cut-m);--grow:6px}
.btn-group .btn+.btn{margin-left:-2px}
/* Button row: buttons side by side, centred on one line; a form in the row gives its buttons to the row */
.btn-row{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem}
.btn-row>form{display:contents}
/* A table row whose cell holds a .btn-row centres every cell, so the text sits level with the buttons */
.table tr:has(>td>.btn-row)>td{vertical-align:middle}
/* Stanze (A02): wrap a button in .press; it sits on a hard shadow and presses into it */
.press{display:inline-flex;filter:drop-shadow(4px 4px 0 var(--bg2))}
.press .btn:active{transform:translate(4px,4px)}
.press:has(.btn:active){filter:drop-shadow(0 0 0 var(--bg2))}
/* Röhre (A09): wrap one button per page in .tube: warm amber glow, warms up on load */
.tube{display:inline-flex;filter:drop-shadow(0 0 14px rgba(250,189,47,.42))}

/* ── Screenshot: same width as the install box ── */
.hero-shot{position:relative;background:var(--bg-panel);border:1px solid var(--bg1)}
.hero-shot img{display:block;width:100%;max-height:26rem;object-fit:cover;object-position:top left}

/* ── Screenshot gallery (several images with captions) ── */
.shots{max-width:var(--max-w-wide);margin:0 auto;padding:4rem var(--gutter) 0;display:grid;
  grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:1.5rem}
.shots figure{position:relative;display:flex;flex-direction:column;gap:.7rem}
.shots img{display:block;width:100%;background:var(--bg-panel);border:1px solid var(--bg1)}
.shots figcaption{font-family:var(--font-mono);font-size:.72rem;letter-spacing:.14em;text-transform:uppercase;color:var(--fg3)}

/* ── Facts strip: three or four big figures with a label ── */
.facts{max-width:var(--max-w-wide);margin:0 auto;padding:3.5rem var(--gutter) 0;
  display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:1.5rem}
.fact{border-top:2px solid var(--bg2);padding-top:1rem}
.fact b{display:block;font-family:var(--font-heading);font-weight:700;font-size:clamp(2.6rem,6vw,4rem);line-height:1;color:var(--yellow)}
.fact b i{font-style:normal}
.fact b .odo-d{display:inline-block;height:1em;overflow:hidden;vertical-align:top}
.fact b .odo-r{display:flex;flex-direction:column;text-align:center}
.fact b .odo-r i{display:block;height:1em;line-height:1}
.fact span{display:block;margin-top:.4rem;font-family:var(--font-mono);font-size:.72rem;letter-spacing:.14em;text-transform:uppercase;color:var(--fg3)}

/* ── Showcase: text beside one screenshot, rows alternate (.rev flips a row) ── */
.showcase{max-width:var(--max-w-wide);margin:0 auto;padding:4rem var(--gutter) 0;
  display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.15fr);gap:3rem;align-items:center}
.showcase.rev{grid-template-columns:minmax(0,1.15fr) minmax(0,1fr)}
.showcase.rev>figure{order:-1}
.showcase-text{display:flex;flex-direction:column;gap:.9rem}
.showcase-tag{font-family:var(--font-mono);font-size:.7rem;letter-spacing:.16em;text-transform:uppercase;color:var(--yellow)}
.showcase h2{font-family:var(--font-heading);font-size:clamp(1.8rem,3.4vw,2.6rem);font-weight:700;text-transform:uppercase;line-height:1.02;color:var(--fg0)}
.showcase p{color:var(--fg2);font-size:.98rem}
.showcase ul{list-style:none;display:flex;flex-direction:column;gap:.45rem}
.showcase li{position:relative;padding-left:1.1rem;color:var(--fg2);font-size:.92rem}
.showcase li::before{content:"";position:absolute;left:0;top:.62em;width:.4rem;height:.4rem;background:var(--yellow)}
.showcase figure{position:relative;background:var(--bg-panel);border:1px solid var(--bg1);
  clip-path:polygon(0 0,calc(100% - var(--chamfer)) 0,100% var(--chamfer),100% 100%,0 100%)}
.showcase figure img{display:block;width:100%;max-height:30rem;object-fit:cover;object-position:top left}
.showcase figure.native{display:flex;flex-direction:column;align-items:center}
.showcase figure.native img{width:auto;max-width:100%;max-height:none;margin:1.1rem auto}
.showcase figure.native figcaption{align-self:stretch}
.showcase figcaption{padding:.55rem .9rem;border-top:1px solid var(--bg1);font-family:var(--font-mono);font-size:.68rem;letter-spacing:.12em;text-transform:uppercase;color:var(--fg3)}

/* ── Changelog (1.17): one entry per release on a rail, newest first; version and date left,
      lead, change groups (new, improved, fixed, note; breaking) and pictures right; older ones
      in a details. note (1.26) is purple: info and links are cyan, which "improved" already has ── */
.changelog{list-style:none;padding:0;margin:1.5rem 0 0;display:flex;flex-direction:column;gap:2.6rem;border-left:2px solid var(--bg2)}
.section .changelog{max-width:var(--max-w-wide)}
.release{position:relative;display:grid;grid-template-columns:9rem minmax(0,1fr);gap:1.6rem;padding-left:1.4rem}
.release::before{content:"";position:absolute;left:-.4rem;top:.55rem;width:.7rem;height:.7rem;background:var(--bg2)}
.release:first-child::before{background:var(--primary)}
.release-head{display:flex;flex-direction:column;gap:.35rem}
.release-version{font-family:var(--font-heading);font-size:1.9rem;font-weight:700;line-height:1;color:var(--fg1)}
.release:first-child .release-version{color:var(--primary)}
.release-head time{font-family:var(--font-mono);font-size:.72rem;letter-spacing:.12em;text-transform:uppercase;color:var(--fg3)}
.release-body{display:flex;flex-direction:column;gap:1rem;min-width:0}
.section .release-lead{color:var(--fg1);font-size:1rem;margin:0}
.release-group h3{display:flex;align-items:center;gap:.5rem;margin-bottom:.45rem;font-family:var(--font-mono);font-size:.7rem;font-weight:500;letter-spacing:.16em;text-transform:uppercase;color:var(--fg3)}
.release-group h3::before{content:"";width:.5rem;height:.5rem;background:var(--kind,var(--fg3))}
.release-group[data-kind="new"]{--kind:var(--aqua)}
.release-group[data-kind="improved"]{--kind:var(--cyan)}
.release-group[data-kind="fixed"]{--kind:var(--orange)}
.release-group[data-kind="note"]{--kind:var(--purple)}
.release-group[data-kind="breaking"]{--kind:var(--red)}
.section .release-group ul{list-style:none;padding:0;display:flex;flex-direction:column;gap:.4rem}
.section .release-group li{position:relative;margin:0;padding-left:1.1rem;color:var(--fg2);font-size:.92rem}
.section .release-group li::before{content:"";position:absolute;left:0;top:.62em;width:.35rem;height:.35rem;background:var(--kind,var(--fg3))}
.release-shots{display:grid;grid-template-columns:repeat(auto-fit,minmax(16rem,1fr));gap:1rem}
.release-shots figure{position:relative;margin:0;background:var(--bg-panel);border:1px solid var(--bg1);
  clip-path:polygon(0 0,calc(100% - var(--chamfer)) 0,100% var(--chamfer),100% 100%,0 100%)}
.release-shots figure>img,.release-shots figure>svg{display:block;width:100%;height:auto}
.release-shots figcaption{padding:.5rem .8rem;border-top:1px solid var(--bg1);font-family:var(--font-mono);font-size:.66rem;letter-spacing:.12em;text-transform:uppercase;color:var(--fg3)}
.release-notes{font-family:var(--font-mono);font-size:.78rem}
details.changelog-more{margin-top:2rem}
details.changelog-more>summary{cursor:pointer;font-family:var(--font-mono);font-size:.78rem;letter-spacing:.12em;text-transform:uppercase;color:var(--link)}
details.changelog-more>.changelog{margin-top:1.5rem}
details.changelog-more .release:first-child::before{background:var(--bg2)}
details.changelog-more .release:first-child .release-version{color:var(--fg1)}
@media (max-width:40rem){.release{grid-template-columns:1fr;gap:.8rem}.release-head{flex-direction:row;align-items:baseline;gap:.8rem}}

/* ── Flow: boxes joined by arrows, e.g. an architecture in one line ── */
.flow{display:flex;align-items:stretch;gap:0;margin-bottom:1rem}
.flow-node{flex:1;background:var(--bg-panel);border-top:4px solid var(--bg2);padding:1rem 1.1rem 1.2rem;
  display:flex;flex-direction:column;gap:.3rem;
  clip-path:polygon(0 0,calc(100% - var(--chamfer)) 0,100% var(--chamfer),100% 100%,0 100%)}
.flow-node.hl{border-top-color:var(--yellow)}
.flow-node b{font-family:var(--font-heading);font-size:1.15rem;font-weight:700;text-transform:uppercase;letter-spacing:.03em;color:var(--fg0)}
.flow-node span{font-size:.82rem;color:var(--fg2);line-height:1.45}
.flow-node code{font-size:.78rem}
.flow-arrow{flex:0 0 2rem;display:flex;align-items:center;justify-content:center;color:var(--cyan);font-family:var(--font-mono)}
.flow-arrow::before{content:"→"}

/* ── Tokens: an input line split into coloured parts (e.g. Quick Add syntax) ── */
.tokens{display:flex;flex-wrap:wrap;gap:.6rem;margin-bottom:1rem}
.tok{display:flex;flex-direction:column;gap:.35rem;min-width:8rem}
.tok code{display:block;background:var(--bg-hard);border-top:3px solid var(--tok,var(--cyan));color:var(--fg0);
  padding:.55rem .8rem;font-family:var(--font-mono);font-size:.95rem}
.tok small{font-family:var(--font-mono);font-size:.66rem;letter-spacing:.12em;text-transform:uppercase;color:var(--fg3)}
.tok[data-k="date"]{--tok:var(--cyan)}
.tok[data-k="prio"]{--tok:var(--red)}
.tok[data-k="tag"]{--tok:var(--yellow)}
.tok[data-k="project"]{--tok:var(--aqua)}
.tok[data-k="text"]{--tok:var(--bg2)}

/* ── FAQ: native details/summary ── */
.faq{display:flex;flex-direction:column;gap:.6rem}
.faq details{background:var(--bg-panel);border-top:4px solid var(--bg2);padding:.2rem 1.1rem;
  clip-path:polygon(0 0,calc(100% - var(--chamfer)) 0,100% var(--chamfer),100% 100%,0 100%)}
.faq details[open]{border-top-color:var(--yellow)}
.faq summary{cursor:pointer;padding:.8rem 0;font-family:var(--font-heading);font-weight:600;font-size:1.15rem;letter-spacing:.02em;color:var(--fg0);list-style:none}
.faq summary::-webkit-details-marker{display:none}
.faq summary::before{content:"+";display:inline-block;width:1.2rem;color:var(--yellow);font-family:var(--font-mono)}
.faq details[open] summary::before{content:"–"}
.faq summary:focus-visible{outline:2px solid var(--focus);outline-offset:-2px}
.faq details>div{padding:0 0 1rem 1.2rem;color:var(--fg2);font-size:.92rem}
.faq details>div p{margin-bottom:.6rem}

/* ── Key caps ── */
kbd{white-space:nowrap;font-family:var(--font-mono);font-size:.78em;padding:.05rem .4rem;border:1px solid var(--bg2);border-bottom-width:2px;background:var(--bg-hard);color:var(--fg1)}

/* ── Badges (shields.io, optional) ── */
.badges{display:flex;flex-wrap:wrap;gap:.5rem;margin-bottom:1rem}
.badges img{height:22px}

/* ── Feature boxes: colour bar on top, tier colour = priority band ── */
.features{display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:1.5rem;
  max-width:var(--max-w-wide);margin:0 auto;padding:4rem var(--gutter) 0}
.feat{--tier:var(--info);position:relative;background:var(--bg-panel);border-top:4px solid transparent;
  padding:1.6rem 1.75rem 2rem;display:flex;flex-direction:column;gap:.75rem}
.feat[data-tier="red"]{--tier:var(--red)}
.feat[data-tier="yellow"]{--tier:var(--yellow)}
.feat[data-tier="blue"],.feat[data-tier="cyan"]{--tier:var(--info)}
.feat::before{content:"";position:absolute;left:0;right:0;top:-4px;height:4px;background:var(--tier);transform-origin:left}
a.feat{color:inherit;text-decoration:none}
a.feat:hover{--chamfer:28px;transform:translateY(-3px);text-decoration:none}
a.feat .feat-tag::after{content:" ›";opacity:0}
a.feat:hover .feat-tag::after,a.feat:focus-visible .feat-tag::after{opacity:1}
a.feat:focus-visible{outline:none}
a.feat::after{content:"";position:absolute;inset:0;pointer-events:none}
a.feat:focus-visible::after{inset:6px;background:var(--brk)}
.feat-tag{font-family:var(--font-mono);font-size:.7rem;letter-spacing:.16em;text-transform:uppercase;color:var(--tier)}
.feat-icon{width:24px;height:24px;color:var(--accent);fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.feat h3{font-family:var(--font-heading);font-size:1.75rem;font-weight:700;text-transform:uppercase;
  letter-spacing:.02em;line-height:1.05;color:var(--fg0)}
.feat p{font-size:.95rem;color:var(--fg2);line-height:1.6}
.section+.features{padding-top:1.5rem}
.feat-img{display:block;width:40px;height:40px}
.feat-links{font-family:var(--font-mono);font-size:.78rem;letter-spacing:.06em}
.feat-muted{color:var(--fg3)}

/* ── Prose sections ── */
.section{max-width:var(--max-w-wide);margin:0 auto;padding:3rem var(--gutter) 0}
.section>*{max-width:var(--max-w)}
.section h2{font-family:var(--font-heading);font-size:1.6rem;font-weight:700;text-transform:uppercase;
  letter-spacing:.04em;color:var(--fg0);margin-bottom:.8rem}
.section p{color:var(--fg2);font-size:.95rem;margin-bottom:.8rem}
.section ul{list-style:disc;padding-left:1.4rem}
.section li{margin-bottom:.4rem;color:var(--fg2);font-size:.95rem}
.section li strong{color:var(--fg1)}

/* ── Steps (numbered) ── */
.steps{list-style:none;counter-reset:step;margin:0;padding:0}
.steps>li{counter-increment:step;position:relative;padding-left:2.6rem;margin-bottom:1.1rem}
.steps>li::before{content:counter(step);position:absolute;left:0;top:.05rem;width:1.8rem;height:1.8rem;
  background:var(--bg-panel);border:1px solid var(--bg2);color:var(--yellow);
  font-family:var(--font-heading);font-weight:700;display:flex;align-items:center;justify-content:center}

/* ── Table ── */
.table-wrap{overflow-x:auto;border:1px solid var(--bg1);background:var(--bg-panel);margin-bottom:1rem}
/* A menu open in a row leaves the frame: no cut and no scroll box while it is open */
.table-wrap:has(details[open]){clip-path:none;overflow:visible}
.table{width:100%;border-collapse:collapse;font-size:.9rem}
.table th{font-family:var(--font-heading);font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--fg0);
  text-align:left;background:var(--bg1);padding:.65rem .9rem;white-space:nowrap}
.table td{padding:.6rem .9rem;color:var(--fg2);border-top:1px solid var(--bg1);vertical-align:top}
.table code{color:var(--fg1)}

/* ── Code block ── */
.codeblock{margin-bottom:1rem;background:var(--bg-hard);border:1px solid var(--bg1);padding:1rem 1.2rem;overflow-x:auto;
  font-family:var(--font-mono);font-size:.85rem;line-height:1.55;color:var(--fg1);white-space:pre}
.codeblock .c{color:var(--fg3)}
.codeblock .k{color:var(--blue)}

/* ── Callout (notes, disclaimers) ── */
.callout{background:var(--bg-panel);border-top:4px solid var(--info);padding:.9rem 1.1rem;font-size:.9rem;color:var(--fg2);margin-bottom:1.2rem}
.callout strong{color:var(--fg1)}
.callout-warn{border-top-color:var(--warn)}
.callout-danger{border-top-color:var(--danger)}
.callout-ok{border-top-color:var(--aqua)}

/* ── Banner: full-width status notice above the nav (e.g. "not ready for primetime") ── */
.banner{position:relative;background:var(--warn);color:var(--bg-void);padding:1.2rem 0}
.banner::before,.banner::after{content:"";position:absolute;left:0;right:0;height:12px;
  background:repeating-linear-gradient(-45deg,var(--bg-void) 0 12px,var(--warn) 12px 24px);background-size:33.94px 33.94px}
.banner::before{top:0}
.banner::after{bottom:0}
.banner-inner{max-width:var(--max-w-wide);margin:0 auto;padding:.9rem var(--gutter);display:flex;flex-direction:column;gap:.5rem}
.banner-title{font-family:var(--font-heading);font-weight:700;text-transform:uppercase;letter-spacing:.04em;line-height:1;font-size:clamp(2rem,7.5vw,5.2rem)}
.banner-text{font-family:var(--font-mono);font-size:.78rem;letter-spacing:.14em;text-transform:uppercase;max-width:60rem}
.banner-danger{background:var(--danger)}
.banner-danger::before,.banner-danger::after{background:repeating-linear-gradient(-45deg,var(--bg-void) 0 12px,var(--danger) 12px 24px);background-size:33.94px 33.94px}

/* ── Footer signature: logo, name, link columns, short yellow line and meta ── */
.foot{margin-top:5rem;border-top:1px solid var(--bg1);background:var(--bg-void)}
.foot-inner{max-width:var(--max-w-wide);margin:0 auto;padding:2.75rem var(--gutter) 0;
  display:flex;justify-content:space-between;align-items:flex-start;gap:3rem 4rem;flex-wrap:wrap}
.foot-brand{display:flex;align-items:center;gap:1.6rem}
.foot-brand img{width:96px;height:96px;flex-shrink:0}
.foot-name{display:block;font-family:var(--font-heading);font-weight:700;text-transform:uppercase;letter-spacing:.2em;
  color:var(--fg0);font-size:clamp(1.7rem,4vw,2.9rem);line-height:1}
.foot-tag{display:block;margin-top:.45rem;font-size:.875rem;color:var(--fg3)}
.foot-cols{display:flex;gap:3.5rem;font-family:var(--font-mono);font-size:.75rem;letter-spacing:.14em;text-transform:uppercase}
.foot-cols div{display:flex;flex-direction:column;gap:.65rem}
.foot-cols h4{font-weight:400;color:var(--fg0)}
.foot-cols a{color:var(--fg3)}
.foot-cols a:hover{color:var(--fg0);text-decoration:none}
.foot-meta{max-width:var(--max-w-wide);margin:0 auto;padding:2.1rem var(--gutter) 2.4rem;
  display:flex;justify-content:space-between;align-items:center;gap:1rem;flex-wrap:wrap}
.foot-meta::before{content:"";width:120px;height:2px;background:var(--yellow)}
.foot-meta p{font-family:var(--font-mono);font-size:.75rem;letter-spacing:.14em;text-transform:uppercase;color:var(--fg3)}
.foot-meta a{color:var(--fg3)}
.foot-meta a:hover{color:var(--fg0)}

/* ── App components (Companion-UI: review, edit, hand over) ─────────────
   Roles, not colours: they follow the theme (dark default, light via data-theme).
   Image stages are dark in BOTH themes (judging colour on a beige ground is
   misleading), so they restore the dark values locally. Group colours:
   green = --aqua, yellow = --yellow, red = --red; status is never colour alone. */
.stage,.tile-img,.strip button{--bg0:#282828;--bg1:#3c3836;--bg2:#504945;--bg-hard:#1d2021;--bg-void:#141312;
  --fg2:#d5c4a1;--fg3:#a89984;--aqua:#8ec07c;--yellow:#fabd2f;--red:#fb4934;--blue:#83a598;--purple:#d3869b;--orange:#fe8019;--cyan:#5ccfc4;--cyan-tint:#1e2b2a;
  --scrim:rgba(20,19,18,.62);--grid:rgba(251,241,199,.22)}

/* 0 · Buttons: see "Buttons" above; they work as <a> and <button>. */

/* 1 · Bildkachel */
.tile{--tier:var(--aqua);position:relative;display:flex;flex-direction:column;text-align:left;cursor:pointer;background:var(--bg-panel);border:0;border-top:4px solid var(--tier);padding:0;
  clip-path:polygon(0 0,calc(100% - var(--chamfer)) 0,100% var(--chamfer),100% 100%,0 100%)}
.tile[data-tier="green"]{--tier:var(--aqua)}.tile[data-tier="yellow"]{--tier:var(--warn)}.tile[data-tier="red"]{--tier:var(--red)}
/* Colour labels: data-label names a colour that is the data itself (e.g. the darktable / Lightroom
   colour label Kader writes), not a tier, so "yellow" stays yellow. Tiers (data-tier) carry meaning */
:is(.tile,.band,.strip button)[data-label="green"]{--tier:var(--aqua)}:is(.tile,.band,.strip button)[data-label="yellow"]{--tier:var(--yellow)}
:is(.tile,.band,.strip button)[data-label="red"]{--tier:var(--red)}:is(.tile,.band,.strip button)[data-label="blue"]{--tier:var(--blue)}
:is(.tile,.band,.strip button)[data-label="purple"]{--tier:var(--purple)}
:is(.tile,.band,.strip button)[data-label="orange"]{--tier:var(--orange)}:is(.tile,.band,.strip button)[data-label="cyan"]{--tier:var(--cyan)}
.tile::after{content:"";position:absolute;inset:0;border:2px solid transparent;pointer-events:none;transition:border-color .12s}
.tile:hover::after{border-color:var(--bg2)}
.tile:focus-visible{outline:0}.tile:focus-visible::after{border-color:transparent;inset:5px;background:var(--brk)}
.tile[aria-selected="true"]::after{border-color:var(--hl)}
.tile-img{display:block;position:relative;aspect-ratio:3/2;background:var(--bg0);overflow:hidden}
.tile-img svg{display:block;width:100%;height:100%}
.tile-crop{position:absolute;inset:var(--in,8%);border:2px dashed var(--tier);pointer-events:none}
.tile-check{position:absolute;top:.4rem;left:.4rem;width:1.1rem;height:1.1rem;background:var(--bg-void);border:2px solid var(--bg2);display:none;align-items:center;justify-content:center;color:var(--bg-void)}
.tile[aria-selected="true"] .tile-check{display:flex;background:var(--hl);border-color:var(--hl)}
.tile-check svg{width:.7rem;height:.7rem;fill:none;stroke:currentColor;stroke-width:3}
.tile-meta{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:.1rem .6rem;padding:.55rem .7rem .7rem;font-family:var(--font-mono);font-size:.7rem;letter-spacing:.06em}
.tile-name{color:var(--fg2);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tile-conf{display:inline-flex;align-items:center;gap:.3rem;color:var(--tier);font-weight:500;font-variant-numeric:tabular-nums}
.tile-conf svg{width:.85rem;height:.85rem;fill:none;stroke:currentColor;stroke-width:2.5}
.tile .pill{max-width:100%}
.tile-sub{overflow-wrap:anywhere;grid-column:1/-1;color:var(--fg3);text-transform:uppercase;letter-spacing:.12em;font-size:.64rem}
.tile-sm .tile-meta{grid-template-columns:1fr;padding:.35rem .5rem .45rem}
.tile-sm .tile-sub,.tile-sm .tile-name{display:none}
.tile .runner,.feat .runner{z-index:1}
.tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:1rem}

/* 2 · Crop-Editor */
.toolbar{display:flex;flex-wrap:wrap;align-items:center;gap:.6rem 1.2rem;background:var(--bg-hard);border:1px solid var(--bg1);padding:.5rem .75rem}
.toolbar-sep{width:1px;align-self:stretch;background:var(--bg2)}
.toolbar-label{font-family:var(--font-mono);font-size:.68rem;letter-spacing:.14em;text-transform:uppercase;color:var(--fg3)}
.stage{position:relative;overflow:hidden;background:var(--bg0);border:1px solid var(--bg1);aspect-ratio:3/2;touch-action:none} /* bewusst rechteckig: Griffe muessen alle Ecken erreichen */
.stage>svg{position:absolute;inset:0;width:100%;height:100%}
.cropbox{position:absolute;left:var(--l);top:var(--t);right:var(--r);bottom:var(--b);border:2px solid var(--yellow);box-shadow:0 0 0 999px var(--scrim);
  background-image:linear-gradient(90deg,transparent calc(33.33% - .5px),var(--grid) 0 calc(33.33% + .5px),transparent 0 calc(66.66% - .5px),var(--grid) 0 calc(66.66% + .5px),transparent 0),
                   linear-gradient(0deg,transparent calc(33.33% - .5px),var(--grid) 0 calc(33.33% + .5px),transparent 0 calc(66.66% - .5px),var(--grid) 0 calc(66.66% + .5px),transparent 0)}
.handle{position:absolute;width:14px;height:14px;background:var(--yellow);border:2px solid var(--bg-void);transform:translate(-50%,-50%);cursor:pointer}
.handle[data-h="nw"]{left:0;top:0;cursor:nwse-resize}.handle[data-h="n"]{left:50%;top:0;cursor:ns-resize}.handle[data-h="ne"]{left:100%;top:0;cursor:nesw-resize}
.handle[data-h="w"]{left:0;top:50%;cursor:ew-resize}.handle[data-h="e"]{left:100%;top:50%;cursor:ew-resize}
.handle[data-h="sw"]{left:0;top:100%;cursor:nesw-resize}.handle[data-h="s"]{left:50%;top:100%;cursor:ns-resize}.handle[data-h="se"]{left:100%;top:100%;cursor:nwse-resize}
.cand{position:absolute;left:var(--l);top:var(--t);right:var(--r);bottom:var(--b);border:1px dashed var(--c,var(--blue));pointer-events:none}
.cand[hidden]{display:none}
.cand-tag.is-right{left:auto;right:14px}
.cand-tag{position:absolute;left:14px;bottom:100%;background:var(--c,var(--blue));color:var(--bg-void);font-family:var(--font-mono);font-size:.62rem;letter-spacing:.06em;padding:.05rem .35rem;white-space:nowrap}
.readout{white-space:nowrap;pointer-events:none;position:absolute;right:.5rem;bottom:.5rem;background:var(--bg-void);border:1px solid var(--bg2);padding:.15rem .5rem;font-family:var(--font-mono);font-size:.68rem;color:var(--fg2);font-variant-numeric:tabular-nums}
.strip{display:flex;gap:.4rem;overflow-x:auto;padding-bottom:.3rem}
.strip button{--tier:var(--aqua);flex:0 0 5.2rem;aspect-ratio:3/2;background:var(--bg0);border:2px solid transparent;border-top:3px solid var(--tier);padding:0;cursor:pointer;overflow:hidden}
.strip button[data-tier="yellow"]{--tier:var(--warn)}.strip button[data-tier="red"]{--tier:var(--red)}
.strip button[aria-current="true"]{border-color:var(--primary);border-top-color:var(--tier)}
.strip svg{display:block;width:100%;height:100%}

/* 3 · Umsortieren (Drag-and-drop) */
.bands{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:.8rem}
.band{--tier:var(--aqua);background:var(--bg-hard);border-top:4px solid var(--tier);padding:.6rem;min-height:9.5rem;display:grid;grid-template-columns:repeat(auto-fill,minmax(72px,1fr));gap:.5rem;align-content:start;transition:background .12s}
.band[data-tier="yellow"]{--tier:var(--warn)}.band[data-tier="red"]{--tier:var(--red)}
.band-head{grid-column:1/-1;display:flex;justify-content:space-between;font-family:var(--font-mono);font-size:.68rem;letter-spacing:.14em;text-transform:uppercase;color:var(--tier)}
.band-head span:last-child{color:var(--fg3);font-variant-numeric:tabular-nums}
.band.is-over{outline:2px dashed var(--tier);outline-offset:-4px;background:var(--bg-panel)}
.tile.is-dragging{opacity:.4}
.band .tile{cursor:grab}
.drag-badge{display:inline-flex;align-items:center;justify-content:center;min-width:1.4rem;height:1.4rem;padding-inline:.3rem;background:var(--hl);color:var(--bg-void);font-family:var(--font-mono);font-size:.72rem;font-weight:500}

/* 4 · Steuerelemente */
.field{display:flex;flex-direction:column;gap:.4rem;min-width:0}
.field>label,.field>.field-label{font-family:var(--font-mono);font-size:.68rem;letter-spacing:.14em;text-transform:uppercase;color:var(--fg3)}
.field-hint{font-size:.78rem;color:var(--fg3)}
.input,.select{background:var(--field);border:1px solid var(--bg2);border-bottom-width:2px;color:var(--fg0);font-family:var(--font-mono);font-size:.85rem;min-height:var(--h-m);padding:.45rem .75rem;width:100%;border-radius:0;appearance:none}
textarea.input{min-height:5.5rem;line-height:1.5;resize:vertical}
.input[aria-invalid="true"]{border-bottom-color:var(--danger)}
.input:disabled,.select:disabled{opacity:.55;cursor:not-allowed}
.field-hint.is-error{color:var(--danger)}
.affix{display:flex}.affix .input{flex:1;min-width:0}
.affix>span{display:flex;align-items:center;padding-inline:.7rem;background:var(--bg1);border-bottom:2px solid var(--bg2);font-family:var(--font-mono);font-size:.74rem;color:var(--fg2)}
.input::placeholder{color:var(--fg3)}
.input:hover,.select:hover{border-color:var(--fg3)}
.input:focus,.select:focus{outline:none;border-color:var(--cyan-n);border-bottom-color:var(--cyan);background-color:var(--cyan-tint)}
/* Keyboard focus also gets the ring every other control has: the tint alone is too faint on a light ground */
.input:focus-visible,.select:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
.select{background-image:linear-gradient(45deg,transparent 50%,var(--fg2) 50%),linear-gradient(135deg,var(--fg2) 50%,transparent 50%);background-position:calc(100% - 1.05rem) 55%,calc(100% - .75rem) 55%;background-size:.3rem .3rem;background-repeat:no-repeat;padding-right:2rem}
.seg{display:inline-flex;border:1px solid var(--bg2);flex-wrap:wrap}
.seg button{background:none;border:0;min-height:calc(var(--h-m) - 2px);padding:0 .9rem;font-family:var(--font-mono);font-size:.72rem;letter-spacing:.1em;color:var(--fg3);cursor:pointer}
.seg button:hover{color:var(--fg0)}.seg button[aria-pressed="true"]{background:var(--primary);color:var(--on-primary)}
/* A segment that cannot be chosen (1.28): muted and struck through, not colour alone; title= can say why */
.seg button:is(:disabled,[aria-disabled="true"]),.seg button:is(:disabled,[aria-disabled="true"]):hover{color:var(--fg3);opacity:.6;text-decoration:line-through;cursor:not-allowed}
/* .seg-fill: segments share the full width in one row (narrow side panels); a label that does not fit ends in … */
.seg.seg-fill{display:flex;flex-wrap:nowrap}.seg-fill button{flex:1 1 auto;min-width:0;padding:0 .5rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.range{--zones:var(--bg2);display:flex;flex-direction:column;gap:.4rem}
.range-row{display:flex;align-items:center;gap:.9rem}
.range input{-webkit-appearance:none;appearance:none;flex:1;min-width:0;height:22px;background:transparent;cursor:pointer}
.range input::-webkit-slider-runnable-track{height:6px;background:var(--zones)}
.range input::-moz-range-track{height:6px;background:var(--zones)}
.range input::-webkit-slider-thumb{-webkit-appearance:none;width:12px;height:22px;margin-top:-8px;background:var(--fg0);border:2px solid var(--bg-void)}
.range input::-moz-range-thumb{width:8px;height:18px;background:var(--fg0);border:2px solid var(--bg-void);border-radius:0}
.range-out{min-width:3.2rem;text-align:right;font-family:var(--font-mono);font-size:.95rem;color:var(--score);font-variant-numeric:tabular-nums}
.switch{display:inline-flex;align-items:center;gap:.7rem;background:none;border:0;cursor:pointer;font-family:var(--font-mono);font-size:.78rem;letter-spacing:.06em;color:var(--fg2);text-align:left}
.switch-track{position:relative;flex:0 0 2.4rem;height:1.2rem;background:var(--bg2)}
.switch-track::after{content:"";position:absolute;top:2px;left:2px;width:calc(1.2rem - 4px);height:calc(1.2rem - 4px);background:var(--fg0)}
.switch[aria-checked="true"] .switch-track{background:var(--primary)}
.switch[aria-checked="true"] .switch-track::after{transform:translateX(1.2rem);background:var(--bg-void)}
.panel-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:1.1rem 1.4rem}
.panel-grid .wide{grid-column:1/-1}

/* 5 · Status & Fortschritt */
.pill{--c:var(--fg3);display:inline-flex;align-items:center;gap:.45rem;min-height:var(--h-xs);padding:0 .6rem;border:1px solid var(--c);color:var(--c);font-family:var(--font-mono);font-size:.68rem;letter-spacing:.14em;text-transform:uppercase;white-space:nowrap}
.pill::before{content:"";width:.45rem;height:.45rem;background:var(--c)}
.pill[data-state="analyzing"]{--c:var(--info)}
.pill[data-state="reviewing"]{--c:var(--info)}.pill[data-state="reviewing"]::before{background:none;border:2px solid var(--c)}
.pill[data-state="locked"]{--c:var(--warn)}.pill[data-state="locked"]::before{clip-path:polygon(50% 0,100% 100%,0 100%)}
.pill[data-state="applied"]{--c:var(--aqua)}.pill[data-state="applied"]::before{content:"✓";width:auto;height:auto;background:none;font-size:.75rem;line-height:1}
.pill[data-state="failed"]{--c:var(--red)}.pill[data-state="failed"]::before{content:"✕";width:auto;height:auto;background:none;font-size:.75rem;line-height:1}
.progress{display:flex;flex-direction:column;gap:.45rem}
.progress-head{display:flex;justify-content:space-between;gap:1rem;font-family:var(--font-mono);font-size:.72rem;letter-spacing:.1em;text-transform:uppercase;color:var(--fg2);font-variant-numeric:tabular-nums}
.progress-bar{display:flex;height:8px;background:var(--bg-hard)}
.progress-bar>i{display:block;height:100%;background:var(--primary);width:var(--p)}
.progress-segs{display:flex;gap:3px}
.progress-segs>i{flex:1;height:10px;background:var(--bg-hard)}
.progress-segs>i.on{background:var(--primary)}
.progress-segs[data-tier="green"]>i.on{background:var(--aqua)}.progress-segs[data-tier="red"]>i.on{background:var(--red)}
.progress-bar.is-indeterminate{background:repeating-linear-gradient(-45deg,var(--yellow) 0 8px,var(--bg-hard) 8px 16px);background-size:22.63px 22.63px}
.progress-bar>i[data-tier="green"]{background:var(--aqua)}.progress-bar>i[data-tier="yellow"]{background:var(--warn)}.progress-bar>i[data-tier="red"]{background:var(--red)}
.toast{position:relative;overflow:hidden;background:var(--bg-panel);border-top:4px solid var(--info);padding:.7rem 1rem;display:flex;align-items:center;gap:.8rem;font-family:var(--font-mono);font-size:.75rem;letter-spacing:.04em;color:var(--fg1);max-width:26rem;
  clip-path:polygon(0 0,calc(100% - var(--cut-m)) 0,100% var(--cut-m),100% 100%,0 100%)}
.toast[data-kind="ok"]{border-top-color:var(--aqua)}.toast[data-kind="warn"]{border-top-color:var(--warn)}.toast[data-kind="error"]{border-top-color:var(--danger)}
/* Remaining time: a 2px line in the kind's colour, shrinking over --life (A14) */
.toast-life{position:absolute;left:0;right:0;bottom:0;height:2px;background:var(--info);transform-origin:left}
.toast[data-kind="ok"] .toast-life{background:var(--aqua)}.toast[data-kind="warn"] .toast-life{background:var(--warn)}.toast[data-kind="error"] .toast-life{background:var(--danger)}

/* 6 · Fertig-Dialog & Sperre */
.scrim{position:absolute;inset:0;background:var(--scrim);display:grid;place-items:center;padding:1rem;z-index:2}
.scrim.is-fixed{position:fixed}
.scrim[hidden]{display:none}
.dialog{background:var(--bg-panel);border-top:4px solid var(--yellow);padding:1.4rem 1.5rem 1.5rem;display:flex;flex-direction:column;gap:1rem;max-width:30rem;width:100%;
  clip-path:polygon(0 0,calc(100% - var(--chamfer)) 0,100% var(--chamfer),100% 100%,var(--chamfer) 100%,0 calc(100% - var(--chamfer)))}
.dialog.is-danger{border-top-color:var(--danger)}
.dialog h3{font-family:var(--font-heading);font-weight:700;font-size:var(--title-m);text-transform:uppercase;letter-spacing:var(--title-track);color:var(--fg0);line-height:1.05}
.dialog-facts{display:grid;grid-template-columns:repeat(3,1fr);gap:1rem}
.dialog-facts .fact b{font-size:2rem}
.dialog-actions{display:flex;flex-wrap:wrap;gap:.7rem;justify-content:flex-end}
.is-locked .tile,.is-locked .band{pointer-events:none}
.is-locked .tile-img{filter:saturate(.55) brightness(.8)}
.is-locked [data-lockable]{opacity:.55;cursor:not-allowed;pointer-events:none}


/* 7 · More controls and small parts (Kante 1.4) */
/* Tabs as notched tabs; shrippen.js slides the yellow tab (A11) */
.tabs{position:relative;display:flex;flex-wrap:wrap;gap:2px;border-bottom:2px solid var(--bg2)}
.tabs button,.tabs a{position:relative;z-index:1;min-height:var(--h-m);display:inline-flex;align-items:center;padding:0 1.2rem;background:var(--bg1);border:0;color:var(--fg3);cursor:pointer;
  font-family:var(--font-mono);font-size:.72rem;letter-spacing:.12em;text-transform:uppercase;text-decoration:none;
  clip-path:polygon(0 0,calc(100% - var(--cut-m)) 0,100% var(--cut-m),100% 100%,0 100%)}
.tabs :is(button,a):hover{color:var(--fg0);text-decoration:none}
.tabs :is(button,a)[aria-selected="true"],.tabs :is(button,a)[aria-current="page"]{background:var(--primary);color:var(--on-primary)}
.tabs :is(button,a):focus-visible{outline:none;box-shadow:inset 0 -3px 0 var(--focus)}
.tabs.has-ind :is(button,a)[aria-selected="true"],.tabs.has-ind :is(button,a)[aria-current="page"]{background:transparent}
.tabs-ind{position:absolute;top:0;bottom:0;left:0;width:0;background:var(--primary);clip-path:polygon(0 0,calc(100% - var(--cut-m)) 0,100% var(--cut-m),100% 100%,0 100%);pointer-events:none}
.tabs .count{margin-left:.45rem}
/* Check box and radio: square box with a drawn tick (A15), radio as a diamond */
.check{position:relative;display:inline-flex;align-items:center;gap:.65rem;cursor:pointer;font-size:.92rem;color:var(--fg1)}
.check input{position:absolute;opacity:0;width:1px;height:1px}
.check-box,.check-dia{position:relative;flex:none;width:20px;height:20px;display:grid;place-items:center}
.check-box{border:2px solid var(--fg3);background:var(--field)}
.check-box svg{width:14px;height:14px;fill:none;stroke:var(--bg-void);stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:20;stroke-dashoffset:20}
.check-dia::before{content:"";width:14px;height:14px;transform:rotate(45deg);border:2px solid var(--fg3);background:var(--field)}
.check-dia::after{content:"";position:absolute;width:6px;height:6px;transform:rotate(45deg) scale(0);background:var(--bg-void)}
.check:hover .check-box,.check:hover .check-dia::before{border-color:var(--fg1)}
.check input:checked+.check-box,.check input:indeterminate+.check-box{background:var(--primary);border-color:var(--primary)}
.check input:checked+.check-box svg{stroke-dashoffset:0}
.check input:indeterminate+.check-box::after{content:"";width:10px;height:2px;background:var(--bg-void)}
.check input:checked+.check-dia::before{background:var(--primary);border-color:var(--primary)}
.check input:checked+.check-dia::after{transform:rotate(45deg) scale(1)}
.check input:focus-visible+:is(.check-box,.check-dia){outline:2px solid var(--focus);outline-offset:3px}
.check:has(input:disabled){color:var(--fg3);cursor:not-allowed}
.check input:disabled+:is(.check-box,.check-dia){opacity:.45}
/* Counter, sticker, status lamp, HUD line */
.count{display:inline-grid;place-items:center;min-width:var(--h-mark);height:var(--h-mark);padding-inline:.3rem;background:var(--primary);color:var(--on-primary);font-family:var(--font-mono);font-size:.68rem;font-weight:500;font-variant-numeric:tabular-nums}
.count[data-kind="info"]{background:var(--info);color:var(--on-state)}.count[data-kind="error"]{background:var(--danger);color:var(--on-state)}
.sticker{display:inline-flex;align-items:center;gap:.5rem;min-height:var(--h-xs);padding:0 .9rem 0 .6rem;background:var(--paper);color:var(--on-paper);font-family:var(--font-mono);font-size:.7rem;font-weight:500;letter-spacing:.1em;text-transform:uppercase;
  clip-path:polygon(0 0,calc(100% - var(--cut-s)) 0,100% var(--cut-s),100% 100%,0 100%)}
.sticker::before{content:"";width:7px;height:7px;background:var(--dot,var(--on-paper))}
.led{display:inline-block;width:10px;height:10px;background:var(--c,var(--info))}
.hud{display:flex;flex-wrap:wrap;gap:.2rem .9rem;font-family:var(--font-mono);font-size:.7rem;letter-spacing:.14em;text-transform:uppercase;color:var(--fg3)}
.hud b{color:var(--yellow);font-weight:500}.hud em{font-style:normal;color:var(--cyan)}
[data-type].is-typing::after{content:"";display:inline-block;width:.6em;height:1.05em;margin-left:.15em;vertical-align:-.18em;background:var(--primary)}
/* Path and pages */
.crumbs{display:flex;flex-wrap:wrap;gap:.4rem;font-family:var(--font-mono);font-size:.74rem;letter-spacing:.08em;text-transform:uppercase;color:var(--fg3)}
.crumbs a{color:var(--fg2)}.crumbs [aria-current]{color:var(--fg0)}
.crumbs>*+*::before{content:"//";margin-right:.4rem;color:var(--cyan-n)}
.pager{display:flex;flex-wrap:wrap;gap:.3rem}
.pager :is(a,button){display:inline-grid;place-items:center;min-width:var(--h-s);height:var(--h-s);padding-inline:.4rem;background:var(--bg-hard);border:1px solid var(--bg2);color:var(--fg2);cursor:pointer;font-family:var(--font-mono);font-size:.76rem;font-variant-numeric:tabular-nums;text-decoration:none}
.pager :is(a,button):hover{border-color:var(--fg3);color:var(--fg0)}
.pager [aria-current="page"]{background:var(--primary);border-color:var(--primary);color:var(--on-primary)}
/* Menu */
.menu{margin:0;list-style:none;background:var(--bg-panel);border-top:2px solid var(--cyan);padding:.35rem 0;min-width:15rem;
  clip-path:polygon(0 0,calc(100% - var(--cut-m)) 0,100% var(--cut-m),100% 100%,0 100%)}
.menu :is(button,a){display:flex;width:100%;align-items:center;gap:.7rem;min-height:36px;padding-inline:.9rem;background:none;border:0;color:var(--fg1);cursor:pointer;font-size:.9rem;text-align:left;text-decoration:none}
.menu :is(button,a):hover,.menu :is(button,a):focus-visible{outline:none;background:var(--cyan-tint);box-shadow:inset 3px 0 0 var(--cyan)}
.menu kbd{margin-left:auto}.menu .is-danger{color:var(--danger)}
.menu hr{border:0;border-top:1px solid var(--bg1);margin:.3rem 0}
/* Loading: three squares, a placeholder */
.loader{display:inline-flex;gap:4px}.loader i{width:9px;height:9px;background:var(--primary)}
.skel{display:flex;flex-direction:column;gap:.5rem}
.skel i{display:block;height:12px;background:linear-gradient(90deg,var(--bg1) 0 40%,var(--bg2) 50%,var(--bg1) 60%);background-size:300% 100%}
.skel i:nth-child(2){width:80%}.skel i:nth-child(3){width:55%}
/* Empty state and drop zone */
.empty{border:1px dashed var(--bg2);padding:1.6rem 1.2rem;display:flex;flex-direction:column;align-items:center;gap:.6rem;text-align:center}
.empty b{font-family:var(--font-heading);font-size:var(--title-s);letter-spacing:var(--title-track);text-transform:uppercase;color:var(--fg0)}
.empty p{font-size:.86rem;color:var(--fg2)}
.drop{border:2px dashed var(--bg2);padding:1.3rem;display:flex;flex-direction:column;align-items:center;gap:.4rem;text-align:center;color:var(--fg2);font-size:.88rem}
.drop:hover,.drop.is-over{border-color:var(--cyan);background:var(--cyan-tint)}
.table tbody tr[aria-selected="true"] td{background:var(--cyan-tint)}
.table tbody tr[aria-selected="true"] td:first-child{box-shadow:inset 3px 0 0 var(--cyan)}
/* Running light (A21): put <span class="runner" aria-hidden="true"></span> in a positioned surface that is working */
.runner{position:absolute;inset:0;padding:2px;pointer-events:none;
  background:conic-gradient(from var(--run),transparent 0 78%,var(--primary) 90%,transparent 100%);
  -webkit-mask:linear-gradient(black 0 0) content-box exclude,linear-gradient(black 0 0);mask:linear-gradient(black 0 0) content-box exclude,linear-gradient(black 0 0)}

/* ── Motion ────────────────────────────────────────────────────────────
   Warm and mechanical: keys, tubes, counters, tabs, lamps. No glitch.
   Everything lives here, only for prefers-reduced-motion: no-preference.
   Entrances need html.motion (set by shrippen.js) and .is-in (set when the
   element scrolls into view), so without the script nothing is hidden. */
@media (prefers-reduced-motion:no-preference){
  html{scroll-behavior:smooth}
  .nav-brand::before{transition:transform var(--dur) var(--ease-snap) .1s}
  .btn{transition:--c1 var(--dur) var(--ease-out),--c2 var(--dur) var(--ease-out),background-color var(--dur-fast),color var(--dur-fast),border-color var(--dur-fast),transform 60ms}
  .press .btn{transition:transform 70ms}
  .press{transition:filter 70ms}
  .btn.is-busy{animation:k-march .7s linear infinite}
  .banner::before,.banner::after{animation:k-march-l 1.4s linear infinite}
  .progress-bar.is-indeterminate{animation:k-march-s .9s linear infinite}
  /* Segment display (A10): a segment switches on like a lamp when it gets .on; --i staggers a row */
  .progress-segs>i.on{animation:k-lamp 260ms steps(3) both;animation-delay:calc(var(--i,0) * 60ms)}
  a.feat{transition:--chamfer var(--dur) var(--ease-out),transform var(--dur) var(--ease-out)}
  a.feat .feat-tag::after{transition:opacity var(--dur-fast)}
  a.feat::after,.tile::after{transition:inset 220ms var(--ease-out),border-color var(--dur-fast)}
  .input,.select{transition:border-color var(--dur-fast),background-color var(--dur-fast)}
  .switch-track{transition:background var(--dur-fast)}
  .switch-track::after{transition:transform var(--dur) var(--ease-snap)}
  .check-box,.check-dia::before{transition:background var(--dur-fast),border-color var(--dur-fast)}
  .check-box svg{transition:stroke-dashoffset 220ms ease-out 40ms}
  .check-dia::after{transition:transform 160ms var(--ease-snap)}
  .tabs :is(button,a){transition:color var(--dur),background var(--dur-fast)}
  .tabs-ind{transition:left 260ms cubic-bezier(.3,.9,.3,1),width 260ms cubic-bezier(.3,.9,.3,1)}
  .chip-pick,.chip-pick>span::before{transition:background-color var(--dur-fast),border-color var(--dur-fast),color var(--dur-fast)}
  .fold>summary::before{transition:transform var(--dur) var(--ease-snap),background-color var(--dur-fast)}
  .modebar>:is(button,a){transition:color var(--dur-fast),background-color var(--dur-fast)}
  .tile-tools{transition:opacity var(--dur-fast),visibility var(--dur-fast)}
  .launch,a.link-tile{transition:background-color var(--dur-fast)}
  .dropzone{transition:border-color var(--dur-fast),background-color var(--dur-fast)}
  .search>:is(kbd,.engine){transition:opacity var(--dur-fast)}
  .login-code{transition:background-color var(--dur-fast)}
  .editbar.is-fixed,.editbar.is-sticky{animation:k-fade var(--dur) var(--ease-out) both}
  .pill[data-state="analyzing"]::before,.led[data-rhythm="atem"]{animation:k-breathe 3s ease-in-out infinite}
  .led[data-rhythm="puls"]{animation:k-breathe 1.2s ease-in-out infinite}
  .led[data-rhythm="takt"]{animation:k-tick 1s steps(1) infinite}
  .loader i{animation:k-hop .9s ease-in-out infinite}.loader i:nth-child(2){animation-delay:.15s}.loader i:nth-child(3){animation-delay:.3s}
  .skel i{animation:k-skel 1.6s linear infinite}
  .runner{animation:k-run 1.8s linear infinite}
  [data-type].is-typing::after{animation:k-blink 1s steps(1) infinite}
  .fact b .odo-r{transition:transform .9s var(--ease-out)}
  .toast{animation:k-toast-in 360ms cubic-bezier(.2,.9,.25,1) both}
  /* Drawer: slides in from the right edge, its scrim fades; both reverse with .is-leaving */
  .sheet.is-drawer{animation:k-drawer-in var(--dur-slow) var(--ease-out) both}
  .sheet.is-drawer.is-leaving{animation:k-drawer-out var(--dur) var(--ease-out) both}
  .scrim:has(+ .sheet.is-drawer){animation:k-fade var(--dur-slow) var(--ease-out) both}
  .scrim:has(+ .sheet.is-drawer.is-leaving){animation:k-fade-out var(--dur) var(--ease-out) both}
  .toast-life{animation:k-life var(--life,4s) linear both}
  /* Nav drawer (1.19): slides in from the left edge, its scrim fades */
  .nav-drawer[open]{animation:k-drawer-left var(--dur-slow) var(--ease-out) both}
  .nav-drawer[open]::backdrop{animation:k-fade var(--dur-slow) var(--ease-out) both}
  .filter-list :is(a,button){transition:background-color var(--dur-fast),color var(--dur-fast)}
  .tube{animation:k-warm 1.4s cubic-bezier(.4,0,.2,1) .2s both}
  .is-changed{animation:k-changed 1100ms ease-out}
  .is-fresh>.live-line{animation:k-fresh 900ms var(--ease-out) both}
  .is-editing>.tile{transition:border-color var(--dur) calc(var(--i,0) * 70ms)}
  .is-editing>.feat::before{transition:background var(--dur) calc(var(--i,0) * 70ms)}
  .is-editing>.feat::after,.is-editing>[data-editable]::after,.is-editing>.tile::after{animation:k-fade var(--dur) both;animation-delay:calc(var(--i,0) * 70ms)}
  /* Kante Gold: shimmer, glide, drifting crackle */
  :root[data-kante="gold"] :is(.progress-bar.is-indeterminate,.btn.is-busy){animation:k-sheen 2.6s linear infinite}
  :root[data-kante="gold"] .banner::before,:root[data-kante="gold"] .banner::after{animation:none}
  :root[data-kante="gold"] body::before{will-change:transform;animation:k-drift 160s linear infinite}
  /* Entrances */
  /* Only elements that shrippen.js marked at load (data-entrance) are hidden until seen: anything
     inserted later (htmx swaps, dialogs) is never left invisible. */
  html.motion .feat[data-entrance]:not(.is-in){opacity:0}
  html.motion .feat[data-entrance].is-in{animation:k-lamp 260ms steps(3) both;animation-delay:calc(var(--i,0) * 55ms)}
  html.motion .feat[data-entrance]:not(.is-in)::before{transform:scaleX(0)}
  html.motion .feat[data-entrance].is-in::before{animation:k-grow var(--dur-slow) var(--ease-out) both;animation-delay:calc(var(--i,0) * 55ms + 120ms)}
  html.motion .tiles>.tile[data-entrance]:not(.is-in){opacity:0}
  html.motion .tiles>.tile[data-entrance].is-in{animation:k-lamp 260ms steps(3) both;animation-delay:calc(var(--i,0) * 55ms)}
  html.motion :is(.hero-shot,.showcase figure,.shots figure)[data-entrance]:not(.is-in){clip-path:polygon(0 0,100% 0,100% 0,0 0)}
  html.motion :is(.hero-shot,.showcase figure,.shots figure)[data-entrance].is-in{animation:k-scan 700ms cubic-bezier(.3,.7,.2,1) both}
  html.motion :is(.hero-shot,.showcase figure,.shots figure)[data-entrance].is-in::after{content:"";position:absolute;left:0;right:0;top:0;height:2px;background:var(--cyan);pointer-events:none;animation:k-scanline 700ms cubic-bezier(.3,.7,.2,1) both}
  .wall-progress>i{animation:k-wall-time var(--wall-time,20s) linear both}
}
@keyframes k-wall-time{from{transform:scaleX(0)}to{transform:none}}
@keyframes k-march{to{background-position:28.28px 0}}
@keyframes k-sheen{from{background-position:100% 0}to{background-position:-150% 0}}
@keyframes k-drift{to{transform:translate3d(480px,480px,0)}}
@keyframes k-march-l{to{background-position:33.94px 0}}
@keyframes k-march-s{to{background-position:22.63px 0}}
@keyframes k-breathe{50%{opacity:.3}}
@keyframes k-tick{0%{opacity:1}12%{opacity:.25}}
@keyframes k-hop{0%,100%{opacity:.25;transform:none}40%{opacity:1;transform:translateY(-4px)}}
@keyframes k-skel{from{background-position:100% 0}to{background-position:-50% 0}}
@keyframes k-run{to{--run:360deg}}
@keyframes k-blink{50%{opacity:0}}
@keyframes k-toast-in{from{transform:translateX(110%)}}
@keyframes k-drawer-in{from{transform:translateX(calc(100% + 1rem))}}
@keyframes k-drawer-out{to{transform:translateX(calc(100% + 1rem))}}
@keyframes k-drawer-left{from{transform:translateX(-100%)}}
@keyframes k-fade-out{to{opacity:0}}
@keyframes k-life{to{transform:scaleX(0)}}
@keyframes k-warm{0%{filter:drop-shadow(0 0 0 transparent) brightness(.55) saturate(.6)}60%{filter:drop-shadow(0 0 18px rgba(250,189,47,.42)) brightness(1.05)}100%{filter:drop-shadow(0 0 14px rgba(250,189,47,.42))}}
@keyframes k-changed{0%{background-color:var(--cyan-tint);box-shadow:inset 3px 0 0 var(--cyan)}100%{background-color:transparent;box-shadow:inset 3px 0 0 transparent}}
@keyframes k-fresh{0%{transform:scaleX(0);opacity:1}70%{transform:scaleX(1);opacity:1}100%{transform:scaleX(1);opacity:0}}
@keyframes k-fade{from{opacity:0}}
@keyframes k-lamp{0%{opacity:0}34%{opacity:.5}67%{opacity:.2}100%{opacity:1}}
@keyframes k-grow{from{transform:scaleX(0)}}
@keyframes k-scan{from{clip-path:polygon(0 0,100% 0,100% 0,0 0)}to{clip-path:polygon(0 0,calc(100% - var(--chamfer)) 0,100% var(--chamfer),100% 100%,0 100%)}}
@keyframes k-scanline{0%{top:0;opacity:1}90%{opacity:1}100%{top:100%;opacity:0}}

/* 8 · Live data: changed value, fresh data, stale data, edit mode, drag and drop (Kante 1.4).
   Behaviour comes from shrippen.js (window.Kante: tick, fresh, stale, edit, settle) and works
   with htmx swaps: [data-live] elements react to text changes, [data-live-tile] surfaces to a
   settled swap. The line of fresh and stale data always sits on the bottom edge of the tile. */
[data-live-tile]{position:relative}
.live-line{position:absolute;left:0;right:0;bottom:0;height:2px;background:var(--cyan);transform:scaleX(0);transform-origin:left;opacity:0;pointer-events:none}
.is-stale>:not(.live-line){opacity:.55}
.is-stale>.live-line{height:4px;transform:none;opacity:1;background:repeating-linear-gradient(-45deg,var(--warn) 0 6px,transparent 6px 12px)}
.is-stale>.live-line::after{content:attr(data-text);position:absolute;right:.6rem;bottom:8px;padding:.05rem .4rem;background:var(--bg-panel);color:var(--warn);
  font-family:var(--font-mono);font-size:.62rem;letter-spacing:.12em;text-transform:uppercase}
.is-changed{background-color:var(--cyan-tint);box-shadow:inset 3px 0 0 var(--cyan)}
/* Edit mode: tier bars turn cyan and four brackets appear on every editable surface */
.is-editing>.tile,.is-editing>.feat,.is-editing>[data-editable]{--tier:var(--cyan)}
.is-editing>.feat::after,.is-editing>[data-editable]::after{content:"";position:absolute;inset:6px;background:var(--brk);pointer-events:none}
.is-editing>.tile::after{border-color:transparent;inset:5px;background:var(--brk)}
[data-editable]{position:relative}
/* Drag and drop: the picked tile, the gap it leaves, the cell it may land in */
.is-picked{box-shadow:inset 0 0 0 2px var(--cyan);background-color:var(--cyan-tint);
  background-image:linear-gradient(var(--cyan),var(--cyan));background-repeat:no-repeat;background-position:right 2px bottom 2px;background-size:10px 10px}
.drop-gap,.drop-cell{background:transparent!important;border:2px dashed var(--cyan);box-shadow:none}
.drop-cell{border-color:var(--bg2)}
.drop-gap>*,.drop-cell>*{visibility:hidden}

/* 9 · Additions from the project integrations (Kante 1.5) ─────────────
   Everything Andon, Kader, Plasmai, Kurrent and FrameWidge kept locally because Kante lacked it. */
/* Native <dialog>: closed dialogs stay closed, no UA border, backdrop = scrim */
dialog.dialog{border-left:0;border-right:0;border-bottom:0;margin:auto;color:var(--fg1)}
dialog.dialog:not([open]){display:none}
dialog.dialog::backdrop{background:var(--scrim)}
/* Toggle state of a button (aria-pressed) */
.btn-outline[aria-pressed="true"],.btn-data[aria-pressed="true"],.btn-quiet[aria-pressed="true"]{--bc:var(--cyan);background-color:var(--cyan-tint);color:var(--fg0);box-shadow:inset 0 -2px 0 var(--cyan)}
/* Inline button for dense rows (hints, tables): the one exception to the 32/40/48 heights */
.btn-inline{--cut:0px;--grow:0px;min-height:var(--h-xs);padding:0 .5rem;font-size:.78rem;letter-spacing:.1em}
/* Chip: an entity or a filter, a colour square and a name; pressed = filled; .chip-x removes it */
.chips-row{display:flex;flex-wrap:wrap;gap:.4rem;align-items:center}
.chip{--c:var(--purple);display:inline-flex;align-items:center;gap:.4rem;height:var(--h-xs);padding-inline:.5rem;border:1px solid var(--c);background:none;color:var(--c);cursor:pointer;
  font-family:var(--font-mono);font-size:.7rem;letter-spacing:.06em;white-space:nowrap}
.chip::before{content:"";width:8px;height:8px;background:var(--c)}
/* A chip never runs out of its row; .is-wrap lets a long chip (a question, a sentence) break onto more lines */
.chip{max-width:100%}
.chip::before{flex:none}
.chip.is-wrap{height:auto;min-height:var(--h-xs);padding-block:.25rem;white-space:normal;text-align:left;line-height:1.35}
.chip[aria-pressed="true"]{background:var(--c);color:var(--on-state)}
.chip[aria-pressed="true"]::before{background:var(--on-state)}
.chip:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
.chip.is-filter{--c:var(--cyan)}
/* A filter chip reads like .chip-pick: hollow square off; on = filled square on a tint (a fill in the entity colour is for entity chips).
   Off is a toggle button with aria-pressed="false" or a filter link without aria-pressed="true"; a chip without
   a state (an action, a suggested question) keeps its filled square */
:is(.chip.is-filter[aria-pressed="false"],a.chip.is-filter:not([aria-pressed="true"]))::before{background:none;box-shadow:inset 0 0 0 2px var(--c)}
.chip.is-filter[aria-pressed="true"]{background:color-mix(in srgb,var(--c) 16%,transparent);color:var(--fg0)}
.chip.is-filter[aria-pressed="true"]::before{background:var(--c)}
.chip-x{background:none;border:0;color:inherit;cursor:pointer;width:16px;height:16px;line-height:1;padding:0;font-family:var(--font-mono)}
/* Pill over an image */
.pill.is-solid{background:color-mix(in srgb,var(--bg-void) 85%,transparent)}
/* Selectable option card (radio card): aria-checked or aria-selected marks the choice */
.option{position:relative;display:flex;gap:.8rem;align-items:flex-start;padding:.9rem 1rem 1rem;background:var(--bg-panel);border:1px solid transparent;border-top:4px solid var(--bg2);cursor:pointer;
  background-origin:border-box;background-repeat:no-repeat;background-position:top right;background-size:var(--cut-m) var(--cut-m);color:var(--fg1);text-align:left;font:inherit;
  clip-path:polygon(0 0,calc(100% - var(--cut-m)) 0,100% var(--cut-m),100% 100%,0 100%)}
.option:hover{background-color:var(--tint-1)}
/* The frame is a border plus the drawn diagonal (as .btn-outline), so it follows the cut */
.option[aria-checked="true"],.option[aria-selected="true"]{border-color:var(--cyan);background-color:var(--cyan-tint);
  background-image:linear-gradient(to bottom left,transparent 50%,var(--cyan) 50%,var(--cyan) calc(50% + 1px),transparent calc(50% + 1px))}
.option:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--focus)}
/* Dropdown: a <details> that shows a .menu */
details.dropdown{position:relative;display:inline-block}
details.dropdown>summary{list-style:none;cursor:pointer}
details.dropdown>summary::-webkit-details-marker{display:none}
details.dropdown>.menu{position:absolute;top:calc(100% + 4px);left:0;z-index:20}
details.dropdown.is-right>.menu{left:auto;right:0}
/* Toast stack: fixed corner, newest at the bottom, a live region */
.toast-stack{--safe-bottom:env(safe-area-inset-bottom,0px);position:fixed;right:1rem;bottom:calc(var(--toast-offset,1rem) + var(--safe-bottom));z-index:50;display:flex;flex-direction:column;align-items:flex-end;gap:.6rem;pointer-events:none}
.toast-stack>*{pointer-events:auto}
/* File input */
.input[type="file"]{padding:0;display:flex;align-items:center;color:var(--fg2)}
.input[type="file"]::file-selector-button{margin:0 .8rem 0 0;border:0;height:calc(var(--h-m) - 3px);padding:0 1rem;background:var(--bg1);color:var(--fg1);cursor:pointer;
  font-family:var(--font-control);font-weight:700;letter-spacing:.14em;text-transform:uppercase}
/* A <label> that wraps its control */
label.field{font-family:var(--font-mono);font-size:.68rem;letter-spacing:.14em;text-transform:uppercase;color:var(--fg3)}
/* Section label (a heading in mono) */
.h-label{font-family:var(--font-mono);font-size:.7rem;font-weight:400;letter-spacing:.14em;text-transform:uppercase;color:var(--fg3);border-bottom:1px solid var(--bg2);padding-bottom:.4rem}
/* Dismissible callout */
.callout{position:relative}
.callout.has-x{padding-right:2.6rem}
.callout-x{position:absolute;top:.5rem;right:.6rem;width:24px;height:24px;background:none;border:0;color:var(--fg3);cursor:pointer;font-family:var(--font-mono)}
.callout-x:hover{color:var(--fg0)}
.callout-x:focus-visible{outline:2px solid var(--focus);outline-offset:0}
/* Flow node done, fact tier */
.flow-node.done{border-top-color:var(--aqua)}
.flow-node.done b::before{content:"✓ ";color:var(--aqua)}
.fact[data-tier="green"]{border-top-color:var(--aqua)}.fact[data-tier="green"] b{color:var(--aqua)}
.fact[data-tier="yellow"]{border-top-color:var(--yellow)}.fact[data-tier="yellow"] b{color:var(--yellow)}
.fact[data-tier="red"]{border-top-color:var(--red)}.fact[data-tier="red"] b{color:var(--red)}
.fact[data-tier="cyan"]{border-top-color:var(--cyan)}.fact[data-tier="cyan"] b{color:var(--cyan)}
.fact[data-label]{--l:var(--fg3);border-top-color:var(--l)}.fact[data-label] b{color:var(--l)}
.progress-bar>i[data-label]{--l:var(--primary);background:var(--l)}
:is(.fact,.progress-bar>i)[data-label="green"]{--l:var(--aqua)}:is(.fact,.progress-bar>i)[data-label="yellow"]{--l:var(--yellow)}
:is(.fact,.progress-bar>i)[data-label="red"]{--l:var(--red)}:is(.fact,.progress-bar>i)[data-label="blue"]{--l:var(--blue)}
:is(.fact,.progress-bar>i)[data-label="purple"]{--l:var(--purple)}
:is(.fact,.progress-bar>i)[data-label="orange"]{--l:var(--orange)}:is(.fact,.progress-bar>i)[data-label="cyan"]{--l:var(--cyan)}
/* Swatch: entity colours are squares; the ring tells where the colour comes from */
.swatch{--c:var(--cyan);--ring:color-mix(in srgb,var(--c) 55%,var(--fg0));display:inline-block;width:18px;height:18px;background:var(--c);flex:none;box-shadow:inset 0 0 0 1px var(--bg2)}
.swatch[data-src="own"]{outline:2px solid var(--ring);outline-offset:2px}
.swatch[data-src="inherited"]{outline:2px dashed var(--ring);outline-offset:2px}
.swatch[data-src="generated"]{outline:2px dotted var(--ring);outline-offset:2px}
.swatch[aria-selected="true"]{outline:2px solid var(--fg0);outline-offset:2px}
.swatch-grid{display:grid;grid-template-columns:repeat(auto-fill,26px);gap:8px}
/* Table: numbers, group rows, total row */
.table .num,.table th.num{text-align:right;font-family:var(--font-mono);font-variant-numeric:tabular-nums}
.table .group-row td{background:var(--bg1);box-shadow:inset 3px 0 0 var(--yellow);font-family:var(--font-mono);font-size:.68rem;letter-spacing:.14em;text-transform:uppercase;color:var(--fg2)}
.table tfoot td{border-top:2px solid var(--yellow);font-family:var(--font-heading);font-weight:700;letter-spacing:.06em;text-transform:uppercase;color:var(--fg0)}
.table tfoot td.num{color:var(--yellow)}
/* Charts: SVG with the data palette --d1 to --d6; squares for marks, 1 px grid */
.chart{display:block;width:100%;height:auto}
.chart text{font-family:var(--font-mono);font-size:var(--chart-text,8px);letter-spacing:.08em;fill:var(--fg3)}
.chart .grid{stroke:var(--bg1);stroke-width:1}
.chart .goal{stroke:var(--yellow);stroke-width:1.5;stroke-dasharray:4 3}
.chart .line{fill:none;stroke-width:2;stroke-linejoin:miter}
.chart .s1{fill:var(--d1);stroke:var(--d1)}.chart .s2{fill:var(--d2);stroke:var(--d2)}.chart .s3{fill:var(--d3);stroke:var(--d3)}
.chart .s4{fill:var(--d4);stroke:var(--d4)}.chart .s5{fill:var(--d5);stroke:var(--d5)}.chart .s6{fill:var(--d6);stroke:var(--d6)}
.chart .line.s1,.chart .line.s2,.chart .line.s3,.chart .line.s4,.chart .line.s5,.chart .line.s6{fill:none}
.spark{display:block;width:100%;height:auto}
.spark path{fill:none;stroke:var(--d4);stroke-width:1.6}
.spark rect{fill:var(--d4)}
/* Uptime strip: one SVG, one column per day, one path per state (ok, warn, bad, off), so a board
   with a hundred strips lays out a hundred elements instead of thousands of flex items:
   <svg class="uptime" viewBox="0 0 30 1" preserveAspectRatio="none" role="img" aria-label="…">
   <path data-state="ok" d="M0 0h.7v1h-.7zM1 0h.7v1h-.7z"/><path data-state="bad" d="M2 0h.7v1h-.7z"/></svg> */
.uptime{display:block;width:100%;max-width:8rem;height:.4rem}
.uptime path{fill:var(--aqua)}
.uptime path[data-state="warn"]{fill:var(--warn)}.uptime path[data-state="bad"]{fill:var(--danger)}.uptime path[data-state="off"]{fill:var(--bg2)}
/* Stacked columns use the same states: viewBox="0 0 <days> 100", per day a column of ok checks with the failed ones on top.
   Day picker: a row of buttons over a chart in .chart-wrap, one per column; the chosen one framed in the focus colour:
   <div class="day-pick"><button type="button" aria-pressed="true" aria-label="Mo 15.09.: outage"></button>…</div> */
.day-pick{position:absolute;inset:0;display:flex}
.day-pick>button{flex:1 1 0;min-width:0;padding:0;background:none;border:0;cursor:pointer}
.day-pick>button:hover{background:var(--tint-1)}
.day-pick>button[aria-pressed="true"]{box-shadow:inset 0 0 0 2px var(--focus)}
.day-pick>button:focus-visible{outline:2px solid var(--focus);outline-offset:-2px}
/* Detail dialog (Kante 1.14): one frame for every detail view of an app, the layout follows from what
   .detail-body holds, so a new layout is a new combination, not a new component:
   <dialog class="dialog detail"><header class="detail-head">…</header>[<div class="detail-line">…</div>]
   <div class="detail-body">[<aside class="detail-side">|<nav class="detail-list">]<section class="detail-main">…</section>[<aside class="detail-side is-end">]</div></dialog>
     side + main = record · list + main = list and detail · main + side.is-end = large view · main alone = timeline, grid, wall, tabs, tasks */
.dialog.detail{max-width:min(82rem,calc(100vw - 2rem));width:100%;max-height:calc(100dvh - 2rem);padding:0;gap:0;overflow:auto}
.detail-head{display:flex;flex-wrap:wrap;align-items:center;gap:.6rem 1rem;padding:1.1rem 1.5rem;border-bottom:1px solid var(--bg1)}
.detail-head>.launch-icon{--icon:2.75rem}
.detail-name{flex:1 1 12rem;display:flex;flex-direction:column;gap:.15rem;min-width:0}
.dialog .detail-name>h3{margin:0;overflow-wrap:anywhere}
.detail-sub{font-family:var(--font-mono);font-size:.72rem;color:var(--fg3);overflow-wrap:anywhere}
.detail-head>.launch-state{font-family:var(--font-mono);font-size:.72rem}
/* Facts as one line under the head: <div class="detail-line"><span><small>Host</small> <b>nas</b></span>…</div> */
.detail-line{display:flex;flex-wrap:wrap;gap:.3rem 1.4rem;padding:.7rem 1.5rem;border-bottom:1px solid var(--bg1);font-size:.8rem}
.detail-line small{font-family:var(--font-mono);font-size:.62rem;letter-spacing:.1em;text-transform:uppercase;color:var(--fg3)}
.detail-line b{font-weight:500;color:var(--fg1)}
.detail-body{display:grid;grid-template-columns:minmax(0,1fr)}
.detail-body:has(>.detail-side:first-child){grid-template-columns:20rem minmax(0,1fr)}
.detail-body:has(>.detail-list:first-child){grid-template-columns:minmax(14rem,19rem) minmax(0,1fr)}
.detail-body:has(>.detail-side.is-end){grid-template-columns:minmax(0,1fr) 18rem}
.detail-side,.detail-list{background:var(--bg1);padding:1.1rem 1.25rem;display:flex;flex-direction:column;gap:.75rem;min-width:0}
.detail-list{padding-inline:.6rem;gap:.15rem}
.detail-list>.h-label{margin:0 .5rem .4rem}
.detail-side .table{font-size:.78rem}
.detail-side .table td{overflow-wrap:anywhere}
.detail-side .table td:first-child{color:var(--fg3);white-space:nowrap}
.detail-main{padding:1.1rem 1.5rem;display:flex;flex-direction:column;gap:1rem;min-width:0}
/* Blocks: a label row (text left, meta right) over a chart, table, list … */
.detail-block{display:flex;flex-direction:column;gap:.4rem;min-width:0}
.detail-label{display:flex;justify-content:space-between;gap:1rem}
/* A small form in a block: fields stacked, the button under them */
.detail-block>form{display:flex;flex-direction:column;gap:.75rem;align-items:flex-start}.detail-block>form>.field{align-self:stretch}
/* A download or link at the label's end: <a href="….csv" download>CSV</a> */
.detail-label>a{color:var(--fg2);text-decoration:none}.detail-label>a:hover,.detail-label>a:focus-visible{color:var(--fg0)}
.detail-facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(9rem,1fr));gap:1rem}
.detail-facts .fact b{font-size:2rem}
.detail-block>.chart,.detail-block>.chart-wrap{height:8rem}
.detail-hero .chart,.detail-hero .chart-wrap{height:13rem}
/* Stacked check columns fill their .chart-wrap (its height comes from the context, e.g. .detail-hero) */
.chart-wrap>svg.uptime{max-width:none;width:100%;height:100%;background:var(--bg-hard)}
/* A table cell in a state colour, the word stays: <td data-state="bad">HTTP 502</td> (ok, warn, bad) */
.table td[data-state="ok"]{color:var(--aqua)}.table td[data-state="warn"]{color:var(--warn)}.table td[data-state="bad"]{color:var(--danger-text)}
.detail-ticks{display:flex;justify-content:space-between;font-family:var(--font-mono);font-size:.62rem;color:var(--fg3)}
.detail-pair{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:1.25rem;align-items:start}
.detail-day{gap:.5rem}
.detail-day-head{display:flex;align-items:baseline;gap:.75rem}
.detail-day-head>h3{margin:0;font-size:1.3rem}
.detail-day .kpi-row{grid-template-columns:repeat(auto-fit,minmax(7.5rem,1fr));gap:.5rem}
.detail-day .kpi>b{font-size:1.3rem}
/* Rows of name | strip or bar | value: <div class="detail-rows"><span>nas</span><svg class="uptime">…</svg><span>vor 5 h</span>…</div> */
.detail-rows{display:grid;grid-template-columns:minmax(6rem,12rem) minmax(0,1fr) auto;gap:.4rem .8rem;align-items:center;font-size:.8rem}
.detail-rows>:nth-child(3n+1){overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.detail-rows>:nth-child(3n){font-family:var(--font-mono);font-size:.72rem;color:var(--fg2);text-align:right;font-variant-numeric:tabular-nums}
.detail-rows>.uptime{max-width:none;height:.7rem}
/* Wall of figures: <div class="detail-wall"><div class="detail-card" data-tier="…"><span>label</span><b>value</b><svg class="spark">…</svg><small>sub</small></div>…</div> */
.detail-wall{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,13rem),1fr));gap:.8rem}
.detail-card{background:var(--bg-panel);border-top:4px solid var(--c,var(--bg2));padding:.8rem .9rem;display:flex;flex-direction:column;gap:.35rem;min-width:0}
.detail-card[data-tier="green"]{border-top-color:var(--aqua)}.detail-card[data-tier="yellow"]{border-top-color:var(--warn)}
.detail-card[data-tier="red"]{border-top-color:var(--danger)}.detail-card[data-tier="cyan"]{border-top-color:var(--cyan)}
.detail-card>span{font-family:var(--font-mono);font-size:.62rem;letter-spacing:.12em;text-transform:uppercase;color:var(--fg3)}
.detail-card>b{font-family:var(--font-heading);font-weight:700;font-size:1.9rem;line-height:1;color:var(--fg0);font-variant-numeric:tabular-nums}
.detail-card[data-tier="yellow"]>b{color:var(--warn)}.detail-card[data-tier="red"]>b{color:var(--danger-text)}
.detail-card>.spark{height:2rem}
.detail-card>small{font-size:.75rem;color:var(--fg2)}
/* Tasks: progress, then one row per task with its action: <div class="detail-task [is-done]"><span class="led"></span><span>text<small>meta</small></span><button class="btn btn-outline btn-sm">…</button></div> */
.detail-progress{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:1rem;align-items:center;font-family:var(--font-mono);font-size:.75rem;color:var(--fg2)}
.detail-tasks{display:flex;flex-direction:column}
.detail-task{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:.8rem;align-items:center;padding:.6rem .2rem;border-bottom:1px solid var(--bg1)}
.detail-task>span:nth-child(2){display:flex;flex-direction:column;font-size:.86rem;color:var(--fg1);min-width:0}
.detail-task small{font-family:var(--font-mono);font-size:.66rem;color:var(--fg3)}
.detail-task.is-done>span:nth-child(2){color:var(--fg3);text-decoration:line-through}
/* Reading text of the large view */
.detail-read{font-size:1rem;line-height:1.7;color:var(--fg1);max-width:65ch}
.detail-read>h3{margin-bottom:.6rem}
.detail-read>p+p{margin-top:.8rem}
/* A picture of the large view: full width, its caption under it */
.detail-figure{display:flex;flex-direction:column;gap:.5rem;margin:0;min-width:0}
.detail-figure>img{display:block;max-width:100%;height:auto;margin:0 auto;background:var(--bg-hard)}
.detail-figure>iframe{display:block;width:100%;height:70vh;border:0;background:var(--bg-hard)}
/* Thumbnails: <div class="detail-thumbs"><figure class="detail-figure"><img><figcaption></figcaption></figure>…</div> */
.detail-thumbs{display:grid;grid-template-columns:repeat(auto-fill,minmax(9rem,1fr));gap:.75rem}
.detail-thumbs>.detail-figure>img{height:12rem;width:100%;object-fit:contain}
.detail-thumbs>.detail-figure>figcaption{font-size:.75rem;color:var(--fg2);overflow-wrap:anywhere}
/* Waiting for the content: <div class="detail-wait"><span class="loader">…</span></div> */
.detail-wait{display:grid;place-items:center;min-height:12rem}
@media(max-width:60rem){
  .detail-body,.detail-body:has(>.detail-side:first-child),.detail-body:has(>.detail-list:first-child),.detail-body:has(>.detail-side.is-end),.detail-pair{grid-template-columns:minmax(0,1fr)}
  .detail-head,.detail-line,.detail-main{padding-inline:1rem}
  .detail-rows{grid-template-columns:minmax(0,7rem) minmax(0,1fr) auto}
  .detail-facts{grid-template-columns:repeat(auto-fit,minmax(7rem,1fr))}
  .detail-facts .fact b{font-size:1.6rem}
}
.legend{margin:0;padding:0;list-style:none;display:flex;flex-wrap:wrap;gap:.3rem 1rem;font-family:var(--font-mono);font-size:.66rem;letter-spacing:.08em;text-transform:uppercase;color:var(--fg2)}
.legend i{display:inline-block;width:10px;height:10px;margin-right:.4rem;vertical-align:-1px;background:var(--c,var(--d1))}
.heat{display:grid;gap:3px}
.heat i{aspect-ratio:1;background:var(--bg-hard)}
.heat i[data-l="1"]{background:color-mix(in srgb,var(--cyan) 22%,var(--bg-hard))}
.heat i[data-l="2"]{background:color-mix(in srgb,var(--cyan) 44%,var(--bg-hard))}
.heat i[data-l="3"]{background:color-mix(in srgb,var(--cyan) 66%,var(--bg-hard))}
.heat i[data-l="4"]{background:var(--cyan)}
/* A year of days: one column per week, Monday on top (<div class="heat is-weeks">, days in order) */
.heat.is-weeks{grid-template-rows:repeat(7,minmax(0,1fr));grid-auto-flow:column;grid-auto-columns:minmax(0,1fr)}
/* Month grid: today = yellow frame, holiday = orange bar, absence = cyan bar, both = split */
.cal{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:2px}
.cal>b{font-family:var(--font-mono);font-size:.6rem;letter-spacing:.1em;color:var(--fg3);font-weight:400;text-align:center;padding-bottom:.2rem}
.cal>i{font-style:normal;position:relative;aspect-ratio:1.2;background:var(--bg-panel);font-family:var(--font-mono);font-size:.7rem;color:var(--fg2);padding:.15rem .3rem;font-variant-numeric:tabular-nums}
.cal>i.we{background:var(--bg-hard);color:var(--fg3)}
.cal>i.today{box-shadow:inset 0 0 0 2px var(--yellow);color:var(--fg0)}
.cal>i.hol::after,.cal>i.abs::after{content:"";position:absolute;left:.3rem;right:.3rem;bottom:.25rem;height:4px;background:var(--orange)}
.cal>i.abs::after{background:var(--cyan)}
.cal>i.hol.abs::after{background:linear-gradient(90deg,var(--orange) 50%,var(--cyan) 50%)}
.cal>i[aria-selected="true"]{background:var(--cyan-tint);box-shadow:inset 0 0 0 2px var(--cyan)}

/* Chart read-out, week and agenda views, curve and band editors (Kante 1.6) */
.chart-wrap{position:relative}
.chart-wrap .readout{right:auto;bottom:auto;top:.4rem;left:0;display:none;background:var(--bg-panel);color:var(--fg1);line-height:1.5}
.chart-wrap.is-reading .readout{display:block}
.chart-wrap .readout b{display:block;font-weight:400;color:var(--fg3);font-size:.6rem}
.chart .probe{stroke:var(--cyan);stroke-width:1}
.chart .mark{fill:var(--bg-panel);stroke-width:2}
.week{--hours:10;display:grid;grid-template-columns:2.2rem repeat(7,minmax(0,1fr));grid-template-rows:1.5rem repeat(var(--hours),2.1rem);gap:0 2px;font-family:var(--font-mono);font-size:.68rem}
.week>b{grid-row:1;text-align:center;font-weight:400;font-size:.6rem;letter-spacing:.1em;color:var(--fg3);align-self:center}
.week>b.today{color:var(--yellow);font-weight:700}
.week>.col{grid-row:2/-1;background:var(--bg-panel)}
.week>.col.we{background:var(--bg-hard)}
.week>.col.today{box-shadow:inset 0 0 0 2px var(--yellow)}
.week>.hr{grid-column:1;color:var(--fg4,var(--fg3));text-align:right;padding-right:.4rem;font-size:.58rem;transform:translateY(-.5em)}
.week>.ev{--c:var(--yellow);position:relative;margin:1px 3px;padding:.15rem .3rem .15rem .6rem;background:color-mix(in srgb,var(--c) 18%,var(--bg-panel));color:var(--fg0);overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font-family:var(--font-sans);font-size:.72rem;cursor:pointer}
.week>.ev::before{content:"";position:absolute;left:0;top:0;bottom:0;width:4px;background:var(--c)}
.week>.ev.warn{--c:var(--orange)}.week>.ev.info{--c:var(--cyan)}.week>.ev.ok{--c:var(--aqua)}
.agenda{display:grid;gap:.9rem;margin:0;padding:0;list-style:none}
.agenda>h4{display:flex;align-items:center;gap:.6rem;margin:0;font-family:var(--font-mono);font-size:.7rem;font-weight:400;letter-spacing:.1em;color:var(--fg3)}
.agenda>h4::after{content:"";flex:1;height:1px;background:var(--bg1)}
.agenda>h4.today{color:var(--yellow);font-weight:700}
.agenda>h4.today::after{background:var(--yellow)}
.agenda .item{--c:var(--yellow);position:relative;display:grid;grid-template-columns:4.4rem 1fr;align-items:center;min-height:2rem;padding-left:.9rem;cursor:pointer}
.agenda .item::before{content:"";position:absolute;left:0;top:.25rem;bottom:.25rem;width:4px;background:var(--c)}
.agenda .item.warn{--c:var(--orange)}.agenda .item.info{--c:var(--cyan)}.agenda .item.ok{--c:var(--aqua)}
.agenda .item>time{font-family:var(--font-mono);font-size:.72rem;color:var(--fg3)}
.agenda .none{color:var(--fg4,var(--fg3));font-size:.8rem}
.curve{display:block;width:100%;height:auto;touch-action:none}
.curve text{font-family:var(--font-mono);font-size:8px;fill:var(--fg3)}
.curve .frame{fill:var(--bg-hard);stroke:var(--bg2)}
.curve .grid{stroke:var(--bg1)}
.curve .line{fill:none;stroke:var(--d1);stroke-width:2;stroke-linejoin:miter}
.curve .pt{fill:var(--bg-panel);stroke:var(--yellow);stroke-width:2;cursor:grab}
.curve .pt:focus,.curve .pt[aria-selected="true"]{fill:var(--yellow);stroke:var(--cyan);outline:0}
.curve .pt:active{cursor:grabbing}
.band-editor{display:grid;gap:.5rem}
.band-editor>.row{display:flex;align-items:center;gap:.7rem}
.band-editor>.row input{width:5.5rem;text-align:right}
.band-editor>.row .unit{font-family:var(--font-mono);font-size:.72rem;color:var(--fg3);flex:1}
.band-editor>.strip{display:flex;height:10px;background:var(--bg-hard)}
.band-editor>.strip>i{display:block;background:var(--c);flex:var(--w) 1 0}
/* KPI with change: the arrow is a shape, never colour alone */
.kpi{display:flex;flex-direction:column;gap:.2rem;container-type:inline-size;min-width:0}
.kpi>b{font-family:var(--font-heading);font-weight:700;font-size:clamp(1.6rem,14cqi,2.8rem);line-height:1;overflow-wrap:anywhere;color:var(--fg0);font-variant-numeric:tabular-nums}
.kpi>span{font-family:var(--font-mono);font-size:.64rem;letter-spacing:.12em;text-transform:uppercase;color:var(--fg3)}
/* Wide KPI with its spark line (24rem of content and up, container query on the .kpi): figures left, the line right
   and as tall as the KPI; the value keeps one line, sized for its half */
.kpi:has(>.spark){position:relative}
@container (min-width:24rem){
  .kpi:has(>.spark)>:not(.spark){max-width:calc(45% - .7rem)}
  .kpi:has(>.spark)>b{white-space:nowrap;overflow-wrap:normal;font-size:clamp(1.6rem,6cqi,2.8rem)}
  .kpi>.spark{position:absolute;inset-block:0;right:0;width:55%;height:auto;margin:0}
}
.kpi-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(150px,100%),1fr));gap:.8rem}
.delta{display:inline-flex;align-items:center;gap:.35rem;font-family:var(--font-mono);font-size:.7rem;letter-spacing:.06em;font-variant-numeric:tabular-nums;color:var(--fg3)}
.delta::before{content:"";width:8px;height:2px;background:currentColor}
.delta.up{color:var(--aqua)}.delta.up::before{width:0;height:0;background:none;border:5px solid transparent;border-bottom:8px solid currentColor;border-top:0}
.delta.dn{color:var(--red)}.delta.dn::before{width:0;height:0;background:none;border:5px solid transparent;border-top:8px solid currentColor;border-bottom:0}
/* Polarity: data-good="down" where falling is good (costs, errors: up red, down green); "none" = arrow only, no judgement */
.delta[data-good="down"].up{color:var(--red)}.delta[data-good="down"].dn{color:var(--aqua)}
.delta[data-good="none"]:is(.up,.dn){color:var(--fg2)}
/* Bulk bar: appears when something is selected; cyan bar because selection is cyan */
.bulk-bar{display:flex;flex-wrap:wrap;align-items:center;gap:.8rem;background:var(--bg1);border-top:4px solid var(--cyan);padding:.5rem .8rem;
  clip-path:polygon(0 0,calc(100% - var(--cut-m)) 0,100% var(--cut-m),100% 100%,0 100%)}
.bulk-bar>.n{font-family:var(--font-heading);font-weight:700;font-size:1.3rem;color:var(--fg0);font-variant-numeric:tabular-nums}
.bulk-bar>.n small{font-family:var(--font-mono);font-size:.62rem;letter-spacing:.12em;text-transform:uppercase;color:var(--fg3);font-weight:400;margin-left:.4rem}
.bulk-bar>.grow{flex:1}
.bulk-bar.is-sticky{position:sticky;bottom:1rem;z-index:5}
.bulk-bar.is-fixed{position:fixed;left:0;right:0;bottom:0;z-index:20}
/* A fixed bar lifts the toasts above it; --bar-h is the app's bar height */
:root:has(.bulk-bar.is-fixed:not([hidden])) .toast-stack{bottom:calc(var(--toast-offset,1rem) + var(--bar-h,3.6rem) + var(--safe-bottom))}
/* ... unless something covers the bar (a full-screen overlay, an open sheet): an element with
   data-covers-bar that is present and not [hidden] (a <dialog> only while open) keeps the toasts down */
:root:has([data-covers-bar]:not([hidden]):not(dialog:not([open]))) .toast-stack.toast-stack{bottom:calc(var(--toast-offset,1rem) + var(--safe-bottom))}
/* Sheet: a panel from the bottom or the side, with an action row */
.sheet{background:var(--bg-panel);border-top:4px solid var(--yellow);padding:1.1rem 1.3rem 1.3rem;display:flex;flex-direction:column;gap:.8rem;
  clip-path:polygon(0 0,calc(100% - var(--chamfer)) 0,100% var(--chamfer),100% 100%,0 100%)}
.sheet>h3{font-family:var(--font-heading);font-weight:700;font-size:var(--title-m);text-transform:uppercase;letter-spacing:var(--title-track);color:var(--fg0);line-height:1.05}
.sheet>.actions{display:flex;flex-wrap:wrap;gap:.6rem;justify-content:flex-end}
.sheet.is-side{position:fixed;top:0;right:0;bottom:0;width:min(26rem,100%);z-index:30;overflow-y:auto;clip-path:none;border-top-width:0;border-left:4px solid var(--yellow)}
/* Drawer: a sheet over the content of its positioned parent (a dialog), on the right. Inset so the
   parent's frame and bar show around it, one surface step raised, cut on the corner that faces the
   content. A .scrim right before it dims what lies below; .is-leaving slides it out (remove the
   drawer on animationend). Its scroll stays inside: a wheel over a short drawer moves nothing behind. */
.sheet.is-drawer{position:absolute;top:1rem;right:1rem;bottom:1rem;z-index:3;width:min(44rem,calc(100% - 2rem));overflow-y:auto;overscroll-behavior:contain;
  background:var(--bg1);clip-path:polygon(var(--chamfer) 0,100% 0,100% 100%,0 100%,0 var(--chamfer))}
/* Setting row: label, hint, control; the reset button only when the value differs */
.setting{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:.15rem 1rem;align-items:center;padding-block:.7rem;border-bottom:1px solid var(--bg1)}
.break{overflow-wrap:anywhere;word-break:break-word}
.setting>b{font-weight:500;color:var(--fg0);font-size:.92rem}
.setting>span{grid-column:1;font-size:.8rem;color:var(--fg3)}
.setting>.ctl{grid-column:2;grid-row:1/3;display:flex;align-items:center;gap:.6rem}
.setting>.ctl .reset{visibility:hidden}
.setting.is-modified>.ctl .reset{visibility:visible}
.setting.is-modified>b::after{content:"";display:inline-block;width:6px;height:6px;margin-left:.5rem;background:var(--cyan);vertical-align:middle}
/* Day strip: one day as a bar, segments at their time, a 2 px "now" mark, hours below.
   A segment's --c (e.g. its project colour) replaces the colour of its kind (Kante 1.8) */
.day-strip{position:relative;height:44px;background:var(--bg-hard);margin-bottom:1.2rem}
.day-strip>i{position:absolute;top:0;bottom:0;background:var(--c,var(--yellow))}
.day-strip>i.is-dim{opacity:.6}
.day-strip>i.is-event{top:auto;height:12px;background:var(--c,var(--cyan))}
.day-strip>.now{position:absolute;top:-4px;bottom:-4px;width:2px;background:var(--cyan)}
.day-strip>.ticks{position:absolute;left:0;right:0;bottom:-1.1rem;display:flex;justify-content:space-between;font-family:var(--font-mono);font-size:.58rem;color:var(--fg3)}
/* All-day lane: right before a .day-strip, one row per all-day event over the whole day,
   named, the event colour as the bottom edge (cyan; --c replaces it) */
.day-allday{display:flex;flex-direction:column;gap:2px;margin-bottom:4px}
.day-allday>span{--c:var(--cyan);display:block;padding:.2rem .6rem;background:var(--bg-hard);border-bottom:4px solid var(--c);color:var(--fg2);font-size:.72rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* Status light of a service */
.status{--k:var(--aqua);background:var(--bg-panel);border-top:4px solid var(--k);padding:.7rem .9rem .8rem;display:flex;flex-direction:column;gap:.3rem;
  clip-path:polygon(0 0,calc(100% - var(--cut-m)) 0,100% var(--cut-m),100% 100%,0 100%)}
.status[data-state="warn"]{--k:var(--warn)}.status[data-state="bad"]{--k:var(--danger)}.status[data-state="off"]{--k:var(--bg2)}
.status>.name{font-family:var(--font-heading);font-weight:700;font-size:var(--title-s);letter-spacing:var(--title-track);text-transform:uppercase;color:var(--fg0)}
.status>.row{display:flex;align-items:center;gap:.5rem;font-family:var(--font-mono);font-size:.68rem;color:var(--fg2)}
.status>.row::before{content:"";width:9px;height:9px;background:var(--k)}
/* A status that opens its entry: <button class="status"> */
button.status{width:100%;border-left:0;border-right:0;border-bottom:0;font:inherit;color:inherit;text-align:start;cursor:pointer}
button.status:hover{background:var(--tint-1)}button.status:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--focus)}
button.status[aria-pressed="true"]{box-shadow:inset 3px 0 0 var(--cyan)}
/* Board editor: add tile, grip, hover strip */
.tile-add{display:grid;place-items:center;min-height:5rem;border:2px dashed var(--bg2);background:none;color:var(--fg3);cursor:pointer;font-family:var(--font-mono);font-size:1.4rem}
.tile-add:hover,.tile-add:focus-visible{border-color:var(--cyan);color:var(--cyan);background:var(--cyan-tint);outline:none}
.grip{display:inline-block;width:12px;height:18px;cursor:grab;flex:none;
  background:radial-gradient(circle,var(--fg3) 1.2px,transparent 1.6px) 0 0/6px 6px}
.tile-strip{display:flex;gap:2px;align-items:center;background:var(--bg-void);border-bottom:1px solid var(--bg2);padding:.15rem .3rem}
/* Clock: an SVG with .face, .tick, .h, .m, .s and .pin */
.clock{display:block;width:var(--size,140px);height:var(--size,140px)}
.clock .face{fill:var(--bg-panel)}
.clock .tick{stroke:var(--fg3);stroke-width:1.5}
.clock .h,.clock .m{stroke:var(--fg0);stroke-linecap:butt}
.clock .s{stroke:var(--yellow);stroke-width:1.2}
.clock .pin{fill:var(--yellow)}
/* Command palette: a query line with a block cursor, a result list with kbd hints */
.palette{background:var(--bg-panel);border-top:4px solid var(--yellow);display:flex;flex-direction:column;
  clip-path:polygon(0 0,calc(100% - var(--chamfer)) 0,100% var(--chamfer),100% 100%,0 100%)}
.palette>.q{display:flex;align-items:center;gap:.6rem;padding:.7rem .9rem;border-bottom:1px solid var(--bg1);font-family:var(--font-mono);font-size:.82rem;color:var(--fg0)}
.palette>.r{display:flex;justify-content:space-between;align-items:center;gap:1rem;padding:.5rem .9rem;font-size:.88rem;color:var(--fg1);cursor:pointer}
.palette>.r[aria-selected="true"]{background:var(--cyan-tint);box-shadow:inset 3px 0 0 var(--cyan)}
/* Link tile: icon, name, state, hints */
/* One surface with .launch (section 11): a.link-tile is the short form, .launch the full one */
:is(a.link-tile,.launch){background:var(--bg-panel);border-top:4px solid var(--c,var(--bg2));color:var(--fg1);text-decoration:none;
  clip-path:polygon(0 0,calc(100% - var(--cut-m)) 0,100% var(--cut-m),100% 100%,0 100%)}
:is(a.link-tile,.launch):hover{background-color:color-mix(in srgb,var(--fg1) 8%,var(--bg-panel));color:var(--fg1);text-decoration:none}
:is(a.link-tile,.launch):focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--focus)}
a.link-tile{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:.2rem .8rem;align-items:center;padding:.8rem 1rem}
a.link-tile>img,a.link-tile>svg{width:28px;height:28px;grid-row:1/3}
a.link-tile>.name{font-family:var(--font-heading);font-weight:700;font-size:var(--title-s);letter-spacing:var(--title-track);text-transform:uppercase;color:var(--fg0)}
a.link-tile>.hint{grid-column:2/4;font-family:var(--font-mono);font-size:.66rem;letter-spacing:.08em;color:var(--fg3)}
/* List row: marker, text, meta; selected = cyan tint with a bar */
.list-row{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:.7rem;min-height:var(--h-m);padding-inline:.8rem;border-bottom:1px solid var(--bg1);color:var(--fg1);cursor:pointer}
.list-row:hover{background:var(--tint-1)}
.list-row[aria-selected="true"]{background:var(--cyan-tint);box-shadow:inset 3px 0 0 var(--cyan)}
.list-row:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--focus)}
button.list-row{width:100%;border:0;border-bottom:1px solid var(--bg1);background:none;font:inherit;text-align:start}
.list-row>.meta{font-family:var(--font-mono);font-size:.7rem;color:var(--fg3);font-variant-numeric:tabular-nums}
/* Settings: grouped side navigation beside the page (levels such as Me / Team / Instance); on narrow screens one column, the page first */
.settings{display:grid;grid-template-columns:minmax(12rem,15rem) minmax(0,1fr);gap:2rem;align-items:start}
.settings-nav{position:sticky;top:1rem;display:flex;flex-direction:column;gap:.15rem;min-width:0}
.settings-nav .h-label:not(:first-child){margin-top:1rem}
.settings-nav a{display:flex;align-items:center;justify-content:space-between;gap:.5rem;min-height:var(--h-s);padding-inline:.8rem;color:var(--fg1);text-decoration:none}
.settings-nav a:hover{background:var(--tint-1);color:var(--fg0)}
.settings-nav a[aria-current="page"]{background:var(--cyan-tint);box-shadow:inset 3px 0 0 var(--cyan);color:var(--fg0)}
.settings-nav a:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--focus)}
.settings-main{min-width:0;display:flex;flex-direction:column;gap:1.2rem}
@media (max-width:48rem){.settings{grid-template-columns:minmax(0,1fr)}.settings-nav{position:static;order:1}}
/* Before and after: a table of changed fields; .was struck through, .now marked like .is-changed, .same spans both */
.table.diff td.was{color:var(--fg3);text-decoration:line-through;overflow-wrap:anywhere}
.table.diff td.now{color:var(--fg0);background:var(--cyan-tint);box-shadow:inset 3px 0 0 var(--cyan);overflow-wrap:anywhere}
.table.diff td.same{color:var(--fg3)}
/* Record on a page: the detail frame in the page flow (full width, no own scroll), tabs as links under the head:
   <article class="dialog detail is-page"><header class="detail-head">…</header><nav class="tabs detail-tabs"><a aria-current="page">…</a>…</nav><div class="detail-body">… */
.dialog.detail.is-page{max-width:none;max-height:none;overflow:visible}
.detail-tabs{margin:.8rem 1.5rem 0}
/* Map frame around a Leaflet (or similar) map: cut corner, dark tiles, square pins, yellow route */
.map-frame{position:relative;border:1px solid var(--bg2);background:var(--bg-hard);
  clip-path:polygon(0 0,calc(100% - var(--chamfer)) 0,100% var(--chamfer),100% 100%,0 100%)}
.map-frame .leaflet-tile-pane{filter:grayscale(1) invert(1) brightness(.6) contrast(.9) sepia(.25)}
.map-pin{display:block;width:14px;height:14px;background:var(--map-marker);border:2px solid var(--bg-void)}
.map-frame{--route:var(--map-route)}
/* Vector map (js/kante-map.js): MapLibre draws a Protomaps basemap in the frame, in Kante's colours.
   <div class="map-frame" data-map='{"route":[[lon,lat],…],"marks":[{"lon":…,"lat":…,"title":"…","state":"bad"}]}'
        data-map-source="….pmtiles | TileJSON URL"></div>; pins are .map-pin, the route --map-route */
.map-frame[data-map]{aspect-ratio:2/1;min-height:12rem;overflow:hidden}
.map-pin[data-state="ok"]{background:var(--aqua)}.map-pin[data-state="warn"]{background:var(--warn)}.map-pin[data-state="bad"]{background:var(--danger)}
.map-frame .maplibregl-ctrl-attrib,.map-frame .maplibregl-ctrl-attrib.maplibregl-compact{background:var(--bg-hard);color:var(--fg3);font-size:.6rem}
.map-frame .maplibregl-ctrl-attrib a{color:var(--fg2)}
.map-frame .maplibregl-ctrl-group{background:var(--bg1);border-radius:0;box-shadow:none;border:1px solid var(--bg2)}
.map-frame .maplibregl-ctrl-group button+button{border-top-color:var(--bg2)}
:root:not([data-theme="light"]) .map-frame .maplibregl-ctrl-icon{filter:invert(.85)}
/* A command line outside the yellow install box */
.cmd-row.is-plain .cmd-box{background:var(--bg-hard);color:var(--cyan)}
.cmd-row.is-plain .copy-btn{background:var(--bg1);border-color:var(--bg1);color:var(--fg1)}

/* Chip pick: a checkbox as a chip (multi-select filter). A real input inside keeps keyboard and forms working; hollow square = off, filled cyan = on */
.chip-pick{position:relative;display:inline-flex;align-items:center;gap:.45rem;min-height:var(--h-xs);padding-inline:.6rem;border:1px solid var(--bg2);color:var(--fg2);cursor:pointer;
  font-family:var(--font-mono);font-size:.72rem;letter-spacing:.06em;white-space:nowrap}
.chip-pick>input{position:absolute;opacity:0;width:1px;height:1px}
.chip-pick>span::before{content:"";display:inline-block;width:8px;height:8px;margin-right:.45rem;border:2px solid var(--fg3);vertical-align:-1px}
.chip-pick>small{font-size:.66rem;color:var(--fg3);font-variant-numeric:tabular-nums}
.chip-pick:hover{border-color:var(--fg3);color:var(--fg0)}
.chip-pick:has(input:checked){border-color:var(--cyan);background:var(--cyan-tint);color:var(--fg0)}
.chip-pick:has(input:checked)>span::before{background:var(--cyan);border-color:var(--cyan)}
.chip-pick:has(input:focus-visible){outline:2px solid var(--focus);outline-offset:2px}
.chip-pick:has(input:disabled){opacity:.5;cursor:not-allowed}
/* Fold: collapsible section with title and count; a <details>, no script. The cut square turns a quarter when open */
.fold{border-bottom:1px solid var(--bg1)}
.fold>summary{display:flex;align-items:baseline;gap:.6rem;min-height:var(--h-m);padding-block:.5rem;cursor:pointer;list-style:none;
  font-family:var(--font-heading);font-weight:700;font-size:var(--title-s);letter-spacing:var(--title-track);text-transform:uppercase;color:var(--fg0)}
.fold>summary::-webkit-details-marker{display:none}
.fold>summary::before{content:"";flex:none;align-self:center;width:10px;height:10px;background:var(--fg3);clip-path:polygon(0 0,60% 0,100% 40%,100% 100%,0 100%);transform:rotate(-90deg)}
.fold:not([open])>summary::before{background:none;box-shadow:inset 0 0 0 2px var(--fg3)}
.fold[open]>summary::before{background:var(--cyan);transform:none}
.fold:not([open])>summary:hover::before{box-shadow:inset 0 0 0 2px var(--fg0)}
.fold[open]>summary:hover::before{background:var(--cyan)}
.fold>summary:focus-visible{outline:2px solid var(--focus);outline-offset:-2px}
.fold>summary>.count{align-self:center;min-width:0;height:auto;padding:0;background:none;color:var(--fg3);font-weight:400}
.fold>.body{padding:.2rem 0 1rem}
/* Feed: title, source and relative age; .is-compact is one line with the age at the right */
.feed{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}
.feed>li{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:.1rem .8rem;padding:.55rem .1rem;border-bottom:1px solid var(--bg1)}
.feed>li:last-child{border-bottom:0}
.feed>li>a{grid-column:1/-1;color:var(--fg1);font-size:.88rem;line-height:1.35}
.feed>li>a:hover{color:var(--link)}
.feed>li>a:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
.feed>li>.src,.feed>li>time{font-family:var(--font-mono);font-size:.66rem;letter-spacing:.08em;text-transform:uppercase;color:var(--fg3);font-variant-numeric:tabular-nums}
.feed>li>time{text-align:right}
.feed.is-compact>li{grid-template-columns:minmax(0,1fr) auto auto;align-items:baseline;padding-block:.35rem}
.feed.is-compact>li>a{grid-column:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Mode bar: a segmented filter row (tag or mode) with counts; scrolls sideways when it does not fit */
.modebar{display:flex;overflow-x:auto;border:1px solid var(--bg2);scrollbar-width:thin;scrollbar-color:var(--bg2) transparent}
.modebar>:is(button,a){flex:none;display:inline-flex;align-items:center;gap:.5rem;min-height:calc(var(--h-m) - 2px);padding:0 .9rem;background:none;border:0;border-right:1px solid var(--bg2);
  color:var(--fg3);font-family:var(--font-mono);font-size:.72rem;letter-spacing:.1em;white-space:nowrap;cursor:pointer}
.modebar>:is(button,a):last-child{border-right:0}
.modebar>:is(button,a):hover{color:var(--fg0);text-decoration:none}
.modebar>:is(button,a)>small{font-size:.66rem;color:var(--fg3);font-variant-numeric:tabular-nums}
.modebar>:is(button,a):is([aria-pressed="true"],[aria-current="true"],[aria-current="page"]){background:var(--cyan-tint);color:var(--fg0);box-shadow:inset 0 -2px 0 var(--cyan)}
.modebar>:is(button,a):focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--focus)}

/* Tier: --tier colours the bar of a tier card, hint card and timeline row (same names as .feat and .tile) */
.tier-card,.hint-card,.timeline>li{--tier:var(--bg2)}
.hint-card{--tier:var(--info)}
:is(.tier-card,.hint-card,.timeline>li)[data-tier="green"]{--tier:var(--aqua)}
:is(.tier-card,.hint-card,.timeline>li)[data-tier="yellow"]{--tier:var(--warn)}
/* Emphasis, not a state: the card of the main thing on a page, or the main kind of a hint (e.g. Kintsugi's
   pitch, progress and acquisition suggestions). The bar takes the primary fill, the text the text-safe yellow */
:is(.tier-card,.hint-card)[data-tier="primary"]{--tier:var(--primary)}
.hint-card[data-tier="primary"] .tier{color:var(--yellow)}
:is(.tier-card,.hint-card,.timeline>li)[data-tier="red"]{--tier:var(--red)}
:is(.tier-card,.hint-card,.timeline>li)[data-tier="blue"],:is(.tier-card,.hint-card,.timeline>li)[data-tier="cyan"]{--tier:var(--info)}
/* Tier card: a card with a tier bar and no click behaviour (a status, not a link) */
.tier-card{display:flex;flex-direction:column;gap:.3rem;padding:.8rem 1rem .9rem;background:var(--bg-panel);border-top:4px solid var(--tier);color:var(--fg2);font-size:.88rem;
  clip-path:polygon(0 0,calc(100% - var(--cut-m)) 0,100% var(--cut-m),100% 100%,0 100%)}
.tier-card>h3,.tier-card>b{font-family:var(--font-heading);font-weight:700;font-size:var(--title-s);letter-spacing:var(--title-track);text-transform:uppercase;color:var(--fg0)}
.tier-card>small{font-family:var(--font-mono);font-size:.66rem;letter-spacing:.08em;color:var(--fg3)}
/* Hint card: tier as icon shape + text + colour (never colour alone), source, expandable "why", actions.
   Icon: red = triangle, yellow = diamond, blue = square, green = check */
.hint-card{display:flex;flex-direction:column;gap:.35rem;padding:.6rem .8rem .7rem;background:var(--bg-panel);border-top:4px solid var(--tier);
  clip-path:polygon(0 0,calc(100% - var(--cut-m)) 0,100% var(--cut-m),100% 100%,0 100%)}
.hint-card>header{display:flex;justify-content:space-between;align-items:center;gap:.6rem;font-family:var(--font-mono);font-size:.64rem;letter-spacing:.1em;text-transform:uppercase;color:var(--fg3)}
.hint-card .tier{display:inline-flex;align-items:center;gap:.4rem;color:var(--tier)}
.hint-card .tier::before{content:"";width:10px;height:10px;background:currentColor}
.hint-card[data-tier="red"] .tier::before{clip-path:polygon(50% 0,100% 100%,0 100%)}
.hint-card[data-tier="red"] .tier{color:var(--danger-text)}
.hint-card[data-tier="yellow"] .tier::before{clip-path:polygon(50% 0,100% 50%,50% 100%,0 50%)}
.hint-card[data-tier="green"] .tier::before{clip-path:polygon(0 55%,20% 35%,40% 55%,85% 5%,100% 25%,40% 95%)}
.hint-card>.title{color:var(--fg0);font-weight:600;font-size:.92rem;line-height:1.35}
a.hint-card>.title:hover,.hint-card>a.title:hover{color:var(--link)}
.hint-card>.due{font-family:var(--font-mono);font-size:.72rem;color:var(--fg2)}
.hint-card>details>summary{cursor:pointer;width:max-content;max-width:100%;font-family:var(--font-mono);font-size:.72rem;color:var(--link)}
.hint-card>details>summary:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
.hint-card>details>p{margin-top:.35rem;padding-left:.7rem;border-left:2px solid var(--bg2);font-size:.84rem;color:var(--fg2)}
.hint-card>.actions{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;margin-top:.15rem}
/* Date tile: a date in a fixed column; day large, month and weekday small; a range may take a second line */
.date-tile{display:grid;justify-items:center;align-content:center;width:3.6rem;flex:none;line-height:1.1;text-align:center;white-space:nowrap;font-family:var(--font-mono);font-size:.62rem;letter-spacing:.1em;text-transform:uppercase;color:var(--fg3)}
.date-tile>b{font-family:var(--font-heading);font-weight:700;font-size:1.5rem;letter-spacing:0;color:var(--fg0);font-variant-numeric:tabular-nums}
/* Timeline: deadlines, a date column and a 4 px state bar; the state is also written out (.state) */
.timeline{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px}
.timeline>li{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:.8rem;padding:.5rem .8rem .5rem 0;background:var(--bg-panel);border-left:4px solid var(--tier)}
.timeline>li>.date-tile{width:4rem}
.timeline>li>.what{display:flex;flex-direction:column;min-width:0;color:var(--fg1);font-size:.9rem;line-height:1.3}
.timeline>li>.what>small{font-family:var(--font-mono);font-size:.66rem;letter-spacing:.06em;color:var(--fg3)}
.timeline>li>.state{font-family:var(--font-mono);font-style:normal;font-size:.68rem;letter-spacing:.08em;text-transform:uppercase;color:var(--fg2);white-space:nowrap}
.timeline>li[data-tier="red"]>.state{color:var(--danger)}
.timeline>li[data-tier="yellow"]>.state{color:var(--warn)}

/* Edit bar: the edit mode of a page (save, discard, history). Cyan, because editing is selection; .is-sticky sticks to the top, .is-fixed to the bottom edge */
.editbar{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem .8rem;background:var(--bg1);border-top:4px solid var(--cyan);padding:.5rem .8rem;
  clip-path:polygon(0 0,calc(100% - var(--cut-m)) 0,100% var(--cut-m),100% 100%,0 100%)}
/* Popovers hanging below the bar need the clip off: the cut corner is given up */
.editbar.has-menu{clip-path:none}
.editbar>.mode{display:inline-flex;align-items:center;gap:.5rem;font-family:var(--font-heading);font-weight:700;font-size:var(--title-s);letter-spacing:var(--title-track);text-transform:uppercase;color:var(--fg0)}
.editbar>.mode::before{content:"";width:10px;height:10px;background:var(--cyan)}
.editbar>.mode small{font-family:var(--font-mono);font-size:.64rem;font-weight:400;letter-spacing:.1em;color:var(--fg3)}
.editbar>.grow{flex:1}
.editbar.is-sticky{position:sticky;top:var(--editbar-top,0);z-index:5}
.editbar.is-fixed{position:fixed;left:0;right:0;bottom:0;z-index:20;padding-bottom:calc(.5rem + env(safe-area-inset-bottom,0px))}
:root:has(.editbar.is-fixed:not([hidden])) .toast-stack{bottom:calc(var(--toast-offset,1rem) + var(--bar-h,3.6rem) + var(--safe-bottom))}
/* Share dialog: one row per subject (user or team) with a right select; a warning callout when credentials go along */
.share{display:flex;flex-direction:column}
.share>.row{display:grid;grid-template-columns:minmax(0,1fr) 10rem auto;align-items:center;gap:.6rem;padding:.55rem 0;border-bottom:1px solid var(--bg1)}
.share .subject{display:flex;align-items:center;gap:.6rem;min-width:0;color:var(--fg0);font-size:.92rem}
.share .subject::before{content:"";flex:none;width:10px;height:10px;background:var(--fg3)}
.share .subject[data-kind="team"]::before{background:var(--purple);clip-path:polygon(50% 0,100% 50%,50% 100%,0 50%)}
.share .subject>small{font-family:var(--font-mono);font-size:.66rem;letter-spacing:.08em;text-transform:uppercase;color:var(--fg3)}
.share>.callout{margin:.8rem 0 0}
/* The field takes its own line when the row is narrow (phone, small dialog) */
.share>.add{display:flex;flex-wrap:wrap;gap:.6rem;margin-top:.8rem}
.share>.add>.input{flex:1 1 12rem;min-width:0}
/* Login: card on a centred page; setup and second factor use the same card. .login-code is one input drawn as six digit boxes */
.login-wrap{min-height:var(--login-min-h,100vh);display:grid;place-items:center;padding:2rem var(--gutter)}
.login{width:100%;max-width:24rem;display:flex;flex-direction:column;gap:1rem;padding:1.6rem 1.6rem 1.4rem;background:var(--bg-panel);border-top:4px solid var(--yellow);
  clip-path:polygon(0 0,calc(100% - var(--chamfer)) 0,100% var(--chamfer),100% 100%,0 100%)}
.login.is-wide{max-width:30rem}
.login>.brand{display:flex;align-items:center;gap:.6rem;font-family:var(--font-heading);font-weight:700;font-size:1.1rem;letter-spacing:.2em;text-transform:uppercase;color:var(--accent)}
.login>.brand>:is(img,svg){width:30px;height:30px}
.login>h1{font-family:var(--font-heading);font-weight:700;font-size:var(--title-m);letter-spacing:var(--title-track);text-transform:uppercase;color:var(--fg0);line-height:1.05}
.login form{display:flex;flex-direction:column;gap:.8rem}
.login label{font-family:var(--font-mono);font-size:.68rem;letter-spacing:.12em;text-transform:uppercase;color:var(--fg3)}
.login .btn{width:100%}
.login .error{color:var(--danger);font-size:.85rem;border-left:3px solid var(--danger);padding-left:.6rem}
.login>.links{display:flex;justify-content:space-between;gap:1rem;font-size:.78rem}
.login-secret{padding:.6rem .8rem;background:var(--bg-hard);border:1px solid var(--bg1);color:var(--cyan);font-family:var(--font-mono);font-size:.8rem;letter-spacing:.12em;overflow-wrap:anywhere}
.login-code{--cell:3rem;--gap:.5rem;--pitch:calc(var(--cell) + var(--gap));display:block;width:calc(6 * var(--pitch) - var(--gap));max-width:100%;height:3.4rem;border:0;border-radius:0;
  padding:0 0 0 calc((var(--cell) - 1ch) / 2);color:var(--fg0);caret-color:var(--cyan);font-family:var(--font-mono);font-size:1.7rem;letter-spacing:calc(var(--pitch) - 1ch);font-variant-numeric:tabular-nums;
  background:linear-gradient(90deg,var(--field) var(--cell),transparent 0) 0 0/var(--pitch) 100% repeat-x,linear-gradient(90deg,var(--bg2) var(--cell),transparent 0) 0 100%/var(--pitch) 2px repeat-x}
.login-code:focus{outline:none;background:linear-gradient(90deg,var(--cyan-tint) var(--cell),transparent 0) 0 0/var(--pitch) 100% repeat-x,linear-gradient(90deg,var(--cyan) var(--cell),transparent 0) 0 100%/var(--pitch) 2px repeat-x}
.login-code[aria-invalid="true"]{background:linear-gradient(90deg,var(--field) var(--cell),transparent 0) 0 0/var(--pitch) 100% repeat-x,linear-gradient(90deg,var(--danger) var(--cell),transparent 0) 0 100%/var(--pitch) 2px repeat-x}
/* Contrast read-out (theme editor): sample, ratio and a badge; the badge carries a mark and text, so colour is never alone */
.contrast{display:inline-flex;align-items:center;gap:.8rem;padding:.35rem .6rem .35rem .35rem;border:1px solid var(--bg2);background:var(--bg-panel)}
.contrast>.sample{display:grid;place-items:center;width:2.4rem;height:2.4rem;border:1px solid var(--bg2);font-family:var(--font-heading);font-weight:700;font-size:1.2rem}
.contrast>.ratio{font-family:var(--font-mono);font-size:.9rem;font-variant-numeric:tabular-nums;color:var(--fg0)}
.contrast>.badge{--k:var(--fg3);display:inline-flex;align-items:center;gap:.3rem;padding:.1rem .45rem;border:1px solid var(--k);color:var(--k);font-family:var(--font-mono);font-weight:500;font-size:.68rem;letter-spacing:.1em}
.contrast>.badge::before{content:"✓";font-size:.75rem;line-height:1}
.contrast[data-level="aaa"]>.badge{--k:var(--aqua);background:var(--k);color:var(--on-state)}
.contrast[data-level="aa"]>.badge{--k:var(--aqua)}
.contrast[data-level="fail"]>.badge{--k:var(--danger)}
.contrast[data-level="fail"]>.badge::before{content:"✕"}

/* 10 · Kante 1.8: day sky, charts by the hour, inputs, tile tools ─────
   Day strip sky and work band: .day (daylight, before the segments so they lie on it), .sun and
   .moon above sunrise and sunset (icons, so round), .work (work hours) under the track.
   .has-sky makes room above the strip, .has-work below it */
.day-strip{--daylight:color-mix(in srgb,var(--yellow) 14%,transparent)}
.day-strip.has-sky{margin-top:1.1rem}
.day-strip.has-work{margin-bottom:1.75rem}
.day-strip.has-work>.ticks{bottom:-1.65rem}
.day-strip>.day{position:absolute;top:0;bottom:0;background:var(--daylight)}
.day-strip>.work{position:absolute;bottom:-8px;height:4px;background:var(--fg3)}
.day-strip>:is(.sun,.moon){position:absolute;top:-17px;width:12px;height:12px;margin-left:-6px;border-radius:50%}
.day-strip>.sun{background:radial-gradient(circle,var(--yellow) 0 3px,transparent 3.5px),repeating-conic-gradient(from -6deg,var(--yellow) 0 12deg,transparent 12deg 45deg);
  -webkit-mask:radial-gradient(circle,black 0 3.2px,transparent 3.4px 4.4px,black 4.6px 6px,transparent 6px);mask:radial-gradient(circle,black 0 3.2px,transparent 3.4px 4.4px,black 4.6px 6px,transparent 6px)}
.day-strip>.moon{box-shadow:inset 3px -1px 0 0 var(--fg2)}
/* Stacked bars with own colours: a part with class .c takes --c (e.g. the project colour);
   .axis labels the scale on the left (text-anchor end); durations are written as h:mm */
.chart .c{fill:var(--c);stroke:var(--c)}
.chart .axis{text-anchor:end}
/* Value axis beside a stretched chart (1.15): SVG text distorts under preserveAspectRatio="none",
   so the scale is HTML. .chart-frame > .chart-axis (labels top to bottom, e.g. max, half, 0; a first
   .unit names the unit) + the chart or .chart-wrap. In a .detail-block the frame takes the chart's height */
.chart-frame{display:grid;grid-template-columns:auto minmax(0,1fr);gap:.3rem .4rem;align-items:stretch}
.chart-axis{display:flex;flex-direction:column;justify-content:space-between;text-align:right;font-family:var(--font-mono);font-size:.6rem;line-height:1;color:var(--fg3);font-variant-numeric:tabular-nums;white-space:nowrap}
.chart-axis .unit{letter-spacing:.08em;text-transform:uppercase}
/* .is-rows: one label centred on each row (categories, e.g. the weekdays of a .heat) */
.chart-axis.is-rows{justify-content:space-around;text-align:left}
.chart-frame>:is(.chart,.chart-wrap),.chart-frame>.chart-wrap>svg.chart{min-width:0;height:100%}
.chart-frame>.detail-ticks{grid-column:2}
.detail-block>.chart-frame:has(>:is(.chart,.chart-wrap)){height:8rem;grid-template-rows:minmax(0,1fr)}.detail-hero .chart-frame:has(>:is(.chart,.chart-wrap)){height:13rem}
/* Read-out of single elements (1.15): data-tip="Label · value" on a bar, cell or strip in a .chart-wrap[data-readout] */
.chart-wrap[data-readout] [data-tip]:hover{opacity:.75}
/* Week timeline: one row per day over the hours, entries as blocks in their colour, the sum right.
   <b> day, .track (+ .today) with <i style="--from:8.25;--to:12;--c:…"> blocks and .now (--at),
   <small> the sum (.is-zero muted). --start and --span set the window (0 and 24 h) */
.week-line{--start:0;--span:24;display:grid;grid-template-columns:2.2rem minmax(0,1fr) auto;align-items:center;gap:3px .7rem;font-family:var(--font-mono);font-size:.64rem;color:var(--fg3)}
.week-line>.scale{grid-column:2;display:flex;justify-content:space-between;font-size:.58rem;line-height:1.6}
.week-line>b{grid-column:1;font-weight:400;letter-spacing:.1em}
.week-line>b.today{color:var(--yellow);font-weight:700}
.week-line>.track{grid-column:2;position:relative;height:22px;background:var(--bg-hard);
  background-image:repeating-linear-gradient(90deg,transparent 0 calc(25% - 1px),var(--bg1) calc(25% - 1px) 25%)}
.week-line>.track.today{box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--yellow) 60%,transparent)}
.week-line>.track>i{position:absolute;top:3px;bottom:3px;left:calc((var(--from) - var(--start)) / var(--span) * 100%);
  width:max(2px,calc((var(--to) - var(--from)) / var(--span) * 100% - 1px));background:var(--c,var(--entity-fallback))}
.week-line>.track>.now{position:absolute;top:-2px;bottom:-2px;width:2px;margin-left:-1px;left:calc((var(--at) - var(--start)) / var(--span) * 100%);background:var(--cyan)}
.week-line>small{grid-column:3;color:var(--fg1);font-size:.72rem;font-variant-numeric:tabular-nums;text-align:right}
.week-line>small.is-zero{color:var(--fg3)}
/* Date and time: the native <input type="date|time"> as a Kante field, figures in mono; the
   picker icon follows the theme (color-scheme) */
.date-field{font-variant-numeric:tabular-nums;max-width:12rem;color-scheme:dark}
:root[data-theme="light"] .date-field{color-scheme:light}
:root[data-kante] .date-field{color-scheme:inherit}
.date-field::-webkit-calendar-picker-indicator{cursor:pointer;opacity:.8}
.date-field::-webkit-calendar-picker-indicator:hover{opacity:1}
/* Search combo: a field that filters a list under it (the app filters, e.g. with htmx); the list
   shows while the input has aria-expanded="true". .has-colors gives every option an entity square
   (--c, or --entity-fallback); the keyboard row is aria-selected; .is-new adds the typed text */
.combo-search{position:relative;align-self:start}
.combo-search>.input{padding-right:2rem;background-image:linear-gradient(45deg,transparent 50%,var(--fg2) 50%),linear-gradient(135deg,var(--fg2) 50%,transparent 50%);
  background-position:calc(100% - 1.05rem) 55%,calc(100% - .75rem) 55%;background-size:.3rem .3rem;background-repeat:no-repeat}
.combo-search>[role="listbox"]{position:absolute;left:0;right:0;top:calc(100% + 2px);z-index:30;margin:0;padding:.3rem 0;list-style:none;max-height:16rem;overflow:auto;
  background:var(--bg-panel);border:1px solid var(--bg2);border-top:2px solid var(--cyan)}
.combo-search>[aria-expanded="false"]~[role="listbox"],.combo-search>[role="listbox"][hidden]{display:none}
.combo-search [role="option"]{display:flex;align-items:center;gap:.6rem;min-height:var(--h-s);padding:0 .8rem;color:var(--fg1);font-size:.9rem;cursor:pointer}
.combo-search.has-colors [role="option"]:not(.is-new)::before{content:"";flex:none;width:10px;height:10px;background:var(--c,var(--entity-fallback))}
.combo-search [role="option"]:hover{background:var(--tint-1)}
.combo-search [role="option"][aria-selected="true"]{background:var(--cyan-tint);box-shadow:inset 3px 0 0 var(--cyan);color:var(--fg0)}
.combo-search [role="option"].is-new{color:var(--cyan)}
.combo-search [role="option"].is-new::before{content:"+";font-family:var(--font-mono);font-weight:700}
/* Tile tools (edit mode): a strip in its own band above the tile, so it never covers the tile's
   name. The slot (.has-tools, set in edit mode) reserves the band; the strip shows on hover and
   focus, always on touch screens (40 px band), on .is-active slots and when .is-floating (one
   shared strip moved between slots) */
.has-tools{--tools-h:var(--h-s);position:relative;padding-top:calc(var(--tools-h) + 2px)}
.tile-tools{position:absolute;top:0;left:0;right:0;z-index:3;height:var(--tools-h);display:flex;align-items:center;gap:2px;padding:0 .2rem;
  background:var(--bg1);border-top:2px solid var(--cyan);visibility:hidden;opacity:0}
.has-tools:is(:hover,:focus-within,.is-active)>.tile-tools,.tile-tools.is-floating{visibility:visible;opacity:1}
/* The strip's empty parts and its grip let the pointer through to the slot below, so a tile can be picked up by its
   band too; only the buttons and links take the pointer */
.tile-tools{pointer-events:none}
.tile-tools>:is(button,a){pointer-events:auto}
.tile-tools>.gap{flex:1}
.tile-tools>small{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--font-mono);font-size:.64rem;color:var(--fg3)}
.tile-tools>:is(button,a){display:inline-grid;place-items:center;flex:none;min-width:calc(var(--tools-h) - 2px);height:calc(var(--tools-h) - 2px);padding:0 .35rem;
  background:none;border:0;color:var(--fg2);cursor:pointer;font-family:var(--font-mono);font-size:.72rem;text-decoration:none}
.tile-tools>:is(button,a):hover,.tile-tools>:is(button,a):focus-visible{outline:none;background:var(--tint-2);color:var(--fg0)}
.tile-tools>:is(button,a):focus-visible{box-shadow:inset 0 0 0 2px var(--focus)}
.tile-tools>[aria-pressed="true"]{color:var(--cyan)}
.tile-tools>.is-danger:is(:hover,:focus-visible){color:var(--danger)}
.tile-tools>.grip{margin:0 .35rem}
/* A floating strip outside a .has-tools slot sets its own band height */
:not(.has-tools)>.tile-tools{--tools-h:var(--h-s)}
@media (hover:none),(pointer:coarse){.has-tools,:not(.has-tools)>.tile-tools{--tools-h:var(--h-m)}.tile-tools{visibility:visible;opacity:1}}

/* 11 · Kante 1.9: chips as links, chart details, heat goals, colour input, phone fixes ───── */
/* A chip may be a link (a filter that navigates): never underlined. Filter chips carry the
   tier of what they filter: data-tier="critical" red, "warn" orange */
a.chip,a.chip:hover{text-decoration:none}
.chip.is-filter[data-tier="critical"]{--c:var(--danger)}
.chip.is-filter[data-tier="critical"]:not([aria-pressed="true"]){color:var(--danger-text)}
.chip.is-filter[data-tier="warn"]{--c:var(--warn)}
/* Charts drawn with preserveAspectRatio="none" (stretched to the card): lines keep their width.
   The spark end mark as a zero-length path <path class="end" d="M x y h0"> stays square.
   .bar.is-prev is the last period (dashed outline, no fill); .goal.is-danger a limit (red).
   Wide viewBoxes (e.g. 0 0 1000 200) scale text down: set --chart-text in viewBox units */
.chart .line,.chart .grid,.chart .goal,.chart .probe,.chart .mark,.chart .now,.spark path{vector-effect:non-scaling-stroke}
.spark .end{fill:none;stroke:var(--d4);stroke-width:5px;stroke-linecap:square}
.chart .bar.is-prev{fill:none;stroke-width:1.5;stroke-dasharray:4 3;vector-effect:non-scaling-stroke}
.chart .bar.is-prev:not(.s1,.s2,.s3,.s4,.s5,.s6,.c){stroke:var(--fg3)}
.chart .goal.is-danger{stroke:var(--danger)}
/* Heat map: .met reached the day's goal (aqua bar), .under missed it (orange bar); --rows fills
   column by column (a year of weeks: --rows:7). .heat-legend shows the scale, less to more */
/* A 1 px ground line keeps the bar apart from a cell of the same hue */
.heat i.met{box-shadow:inset 0 -2px 0 var(--aqua),inset 0 -3px 0 var(--bg-void)}
.heat i.under{box-shadow:inset 0 -2px 0 var(--warn),inset 0 -3px 0 var(--bg-void)}
.heat[style*="--rows"]{grid-auto-flow:column;grid-template-rows:repeat(var(--rows),auto);grid-auto-columns:minmax(0,1fr)}
.heat-legend{display:flex;align-items:center;gap:3px;font-family:var(--font-mono);font-size:.62rem;letter-spacing:.08em;text-transform:uppercase;color:var(--fg3)}
.heat-legend>i{width:10px;height:10px;background:var(--bg-hard)}
.heat-legend>i[data-l="1"]{background:color-mix(in srgb,var(--cyan) 22%,var(--bg-hard))}
.heat-legend>i[data-l="2"]{background:color-mix(in srgb,var(--cyan) 44%,var(--bg-hard))}
.heat-legend>i[data-l="3"]{background:color-mix(in srgb,var(--cyan) 66%,var(--bg-hard))}
.heat-legend>i[data-l="4"]{background:var(--cyan)}
.heat-legend>i.met{box-shadow:inset 0 -3px 0 var(--aqua),inset 0 -4px 0 var(--bg-void)}.heat-legend>i.under{box-shadow:inset 0 -3px 0 var(--warn),inset 0 -4px 0 var(--bg-void)}
.heat-legend>span{margin-inline:.35rem}
/* Colour input: a square swatch in the Kante field frame */
input[type="color"],.input[type="color"]{appearance:none;-webkit-appearance:none;flex:none;width:var(--h-m);height:var(--h-m);min-height:0;padding:4px;
  background:var(--field);border:1px solid var(--bg2);border-bottom-width:2px;border-radius:0;cursor:pointer}
input[type="color"]::-webkit-color-swatch-wrapper{padding:0}
input[type="color"]::-webkit-color-swatch{border:0;border-radius:0}
input[type="color"]::-moz-color-swatch{border:0;border-radius:0}
input[type="color"]:hover{border-color:var(--fg3)}
input[type="color"]:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
/* Pills in a tile or a badge row shorten with an ellipsis instead of widening the tile */
.tile-badges{display:flex;flex-wrap:wrap;gap:.3rem;min-width:0}
.tile .pill,.tile-badges .pill{display:inline-block;max-width:100%;overflow:hidden;text-overflow:ellipsis;vertical-align:middle;line-height:calc(var(--h-xs) - 2px);letter-spacing:.06em;padding-inline:.4rem}
.tile .pill::before,.tile-badges .pill::before{display:inline-block;margin-right:.3rem;vertical-align:1px}
/* App page head: the title with its actions, apart from the first card or panel under it */
.page-head{display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:space-between;gap:.6rem 1rem;margin-bottom:1.25rem}
.page-head>h1,.page-head>h2{margin:0}
:is(main,.app)>h1+:is(.card,.panel,.feat,.tiles,.panel-grid,.table,.callout,.hint-card,form){margin-top:1.25rem}

/* Launch tile (start page link): icon or monogram, title with host, description, a live line with
   state, info and hint count, a hotkey. Sizes: data-size="small" (one line), "large" (icon tile),
   on the tile or on its .launch-grid. --c tints the top bar and the monogram */
.launch-grid{--tile:15rem;display:grid;grid-template-columns:repeat(auto-fill,minmax(min(var(--tile),100%),1fr));gap:4px;margin:0;padding:0;list-style:none}
.launch-grid[style*="--cols"]{grid-template-columns:repeat(var(--cols),minmax(0,1fr))}
.launch-grid[data-size="small"]{--tile:10rem}.launch-grid[data-size="large"]{--tile:7rem}
.launch{--icon:2.2rem;position:relative;display:flex;align-items:center;gap:.75rem;min-width:0;height:100%;padding:.6rem .8rem .6rem .7rem}
.launch.is-first{box-shadow:inset 0 0 0 1px var(--hl)}
.launch-icon{flex:none;display:grid;place-items:center;width:var(--icon);height:var(--icon)}
.launch-icon>img,.launch-icon>svg{width:100%;height:100%;object-fit:contain}
.launch-icon>.emoji{font-size:calc(var(--icon) * .75);line-height:1}
.launch-icon>.monogram{width:100%;height:100%;display:grid;place-items:center;background:var(--bg-hard);color:var(--c,var(--accent));border-bottom:2px solid currentColor;
  font-family:var(--font-heading);font-weight:700;font-size:calc(var(--icon) * .45);letter-spacing:.02em;text-transform:uppercase}
/* Glyph sets (black shapes, e.g. simple-icons) turn light on a dark ground */
.launch-icon>img.is-glyph{filter:invert(.9)}
:root:is([data-theme="light"],[data-kante="light"]) .launch-icon>img.is-glyph{filter:none}
@media (prefers-color-scheme:dark){:root[data-kante="light"] .launch-icon>img.is-glyph{filter:invert(.9)}}
.launch-body{display:flex;flex-direction:column;flex:1;min-width:0}
.launch-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--font-heading);font-weight:700;font-size:var(--title-s);line-height:1.25;letter-spacing:var(--title-track);text-transform:uppercase;color:var(--fg0)}
.launch-title>small{font-family:var(--font-mono);font-weight:400;font-size:.62rem;letter-spacing:.02em;text-transform:none;color:var(--fg3)}
.launch-desc{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.8rem;line-height:1.35;color:var(--fg2)}
.launch-tags{display:flex;flex-wrap:wrap;gap:0 .5rem;font-family:var(--font-mono);font-size:.62rem;color:var(--fg3)}
.launch-live{display:flex;flex-wrap:wrap;align-items:center;gap:.2rem .7rem;min-height:1.1rem;margin-top:.2rem;font-family:var(--font-mono);font-size:.64rem;letter-spacing:.04em;color:var(--fg2)}
/* State: square plus word (data-state ok, warn, bad, off), like .status */
.launch-state{--k:var(--aqua);display:inline-flex;align-items:center;gap:.35rem;text-transform:uppercase;letter-spacing:.1em}
.launch-state::before{content:"";flex:none;width:7px;height:7px;background:var(--k)}
.launch-state[data-state="warn"]{--k:var(--warn)}.launch-state[data-state="bad"]{--k:var(--danger);color:var(--danger)}.launch-state[data-state="off"]{--k:var(--bg2);color:var(--fg3)}
.launch-info.is-error{color:var(--danger)}
/* Uptime strip with its detail button on one line: <span class="launch-trend"><svg class="uptime">…</svg>
   <span class="launch-detail" role="button" tabindex="0" aria-label="…"><svg>…</svg></span></span>; a span, as the tile is a link */
.launch-trend{flex-basis:100%;display:flex;align-items:center;gap:.4rem;min-width:0}
/* Right half of a wide tile (24rem of content width and up): a column beside the icon and text, e.g. a trend. Hidden on narrower tiles.
   <span class="launch-wide"><svg class="spark">…</svg><span class="launch-info">…</span></span> in .launch-live; the text keeps the left half */
.launch{container-type:inline-size}
.launch-wide{display:none}
@container (min-width:24rem){
  .launch-body:has(.launch-wide){max-width:calc(50% - 4.2rem)}
  .launch-wide{display:flex;flex-direction:column;justify-content:center;gap:.3rem;position:absolute;inset-block:.6rem;left:50%;right:2.4rem;padding-left:1rem;border-left:1px solid var(--bg2);white-space:nowrap}
  .launch-wide .spark{height:1.8rem}
}
.launch-detail{flex:none;display:inline-grid;place-items:center;width:1.6rem;height:var(--h-mark);padding:0;background:none;border:1px solid transparent;color:var(--fg3);cursor:pointer}
.launch-detail svg{width:14px;height:14px}
.launch-detail:hover{color:var(--fg0);border-color:var(--bg2)}
/* Sub-links under a launch tile (1.16): a list after the .launch, indented to its title (padding + icon + gap) */
.launch-items{list-style:none;margin:0;padding:.2rem .6rem .5rem calc(.7rem + 2.2rem + .75rem);display:flex;flex-wrap:wrap;gap:.2rem .9rem;font-family:var(--font-mono);font-size:.72rem}
.launch-items a{display:inline-flex;align-items:center;gap:.3rem;color:var(--fg2);text-decoration:none}
.launch-items a:hover{color:var(--fg0)}
.launch-items img{width:.9rem;height:.9rem;object-fit:contain}
.launch-detail:focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--focus)}
@media (pointer:coarse){.launch-detail{width:2.2rem;height:2rem}}
/* Hint count: outlined in the tier colour; red is filled, so the shape tells the tier too */
.launch-hints{--k:var(--info);display:inline-flex;align-items:center;justify-content:center;gap:.2rem;min-width:var(--h-mark);height:var(--h-mark);margin:0;padding:0 .3rem;background:none;border:1px solid var(--k);color:var(--k);
  font-family:var(--font-mono);font-weight:500;font-size:.62rem;font-variant-numeric:tabular-nums;text-decoration:none;cursor:pointer}
.launch-hints[data-tier="yellow"]{--k:var(--warn)}
.launch-hints[data-tier="red"]{--k:var(--danger);background:var(--danger);color:var(--on-state)}
.launch-hints:hover{background:var(--tint-2)}.launch-hints[data-tier="red"]:hover{background:var(--danger)}
.launch-hints:focus-visible{outline:2px solid var(--focus);outline-offset:1px}
/* Tier by shape as well as colour (as in .hint-card .tier): square info, diamond warning, triangle critical. */
.launch-hints::before{content:"";flex:none;width:6px;height:6px;background:currentColor}
.launch-hints[data-tier="yellow"]::before{clip-path:polygon(50% 0,100% 50%,50% 100%,0 50%)}
.launch-hints[data-tier="red"]::before{clip-path:polygon(50% 0,100% 100%,0 100%)}
.launch-key{align-self:flex-start;font-size:.62rem}
/* small: one line, the state as a square only (the word stays for screen readers) */
:is(.launch[data-size="small"],.launch-grid[data-size="small"] .launch){--icon:1.5rem;gap:.55rem;min-height:var(--h-m);padding:.3rem .6rem .3rem .45rem;border-top-width:2px}
:is(.launch[data-size="small"],.launch-grid[data-size="small"] .launch) .launch-body{flex-direction:row;align-items:center;gap:.5rem}
:is(.launch[data-size="small"],.launch-grid[data-size="small"] .launch) .launch-title{flex:1;font-size:.95rem}
:is(.launch[data-size="small"],.launch-grid[data-size="small"] .launch) .launch-live{flex:none;flex-wrap:nowrap;gap:.4rem;margin:0}
:is(.launch[data-size="large"],.launch-grid[data-size="large"] .launch){--icon:2.8rem;flex-direction:column;justify-content:center;gap:.45rem;padding:1.4rem .4rem .6rem;text-align:center}
:is(.launch[data-size="large"],.launch-grid[data-size="large"] .launch) .launch-body{width:100%;align-items:center}
:is(.launch[data-size="large"],.launch-grid[data-size="large"] .launch) .launch-title{width:100%;font-size:.85rem}
:is(.launch[data-size="large"],.launch-grid[data-size="large"] .launch) .launch-live{position:absolute;inset:.35rem .4rem auto;margin:0;justify-content:space-between}
:is(.launch[data-size="small"],.launch-grid[data-size="small"] .launch,.launch[data-size="large"],.launch-grid[data-size="large"] .launch) :is(.launch-desc,.launch-tags,.launch-info,.launch-key,.launch-title>small){display:none}
:is(.launch[data-size="small"],.launch-grid[data-size="small"] .launch,.launch[data-size="large"],.launch-grid[data-size="large"] .launch) .launch-state{font-size:0;gap:0}
/* Search: filter the page, Enter searches the web. Hotkey in mono on the right; while typing,
   .engine names where Enter goes. .search-empty says nothing matched */
.search{position:relative;display:flex;align-items:center;flex:1 1 16rem;min-width:0;margin:0}
.search::before{content:"›";position:absolute;left:.75rem;font-family:var(--font-mono);font-size:1rem;line-height:1;color:var(--cyan);pointer-events:none}
.search>input{flex:1;min-width:0;margin:0;padding-left:1.8rem;padding-right:3.2rem}
.search>:is(kbd,.engine){position:absolute;right:.55rem;pointer-events:none}
.search>.engine{font-family:var(--font-mono);font-size:.62rem;letter-spacing:.1em;text-transform:uppercase;color:var(--fg3);opacity:0}
.search:focus-within>kbd,.search:has(>input:not(:placeholder-shown))>kbd{opacity:0}
.search:has(>input:not(:placeholder-shown))>.engine{opacity:1}
.search-empty{font-family:var(--font-mono);font-size:.72rem;letter-spacing:.06em;color:var(--fg3)}
/* Clock and weather: compact head widgets. Time and temperature in Rajdhani with tabular digits,
   place and date in mono. A .clock face in a .clock-zone sits left of the text */
.clock-zones{display:flex;flex-wrap:wrap;gap:.6rem 1.6rem}
.clock-zone{display:flex;flex-wrap:wrap;align-items:baseline;align-content:flex-start;gap:0 .5rem;min-width:0}
.clock-zone>*{white-space:nowrap}
.clock-zone>strong,.weather>b{font-family:var(--font-heading);font-weight:700;font-size:1.4rem;line-height:1.1;letter-spacing:.02em;color:var(--fg0);font-variant-numeric:tabular-nums}
.clock-zone>:is(small,span),.weather>small{font-family:var(--font-mono);font-size:.64rem;letter-spacing:.1em;text-transform:uppercase;color:var(--fg3)}
.clock-zone:has(>.clock){display:grid;grid-template-columns:auto minmax(0,1fr);align-items:center;column-gap:.8rem}
.clock-zone>.clock{--size:4.2rem;grid-row:span 3}
.weather{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 .5rem;min-width:0}
.weather>:is(img,svg){align-self:center;width:1.5rem;height:1.5rem}
.weather>span{font-size:.85rem;color:var(--fg1)}
.weather-days{display:grid;grid-template-columns:auto auto minmax(0,1fr);gap:.25rem .9rem;margin:.6rem 0 0;padding:0;list-style:none;font-size:.8rem;color:var(--fg2)}
.weather-days>li{display:contents}
.weather-days>li>:first-child{font-family:var(--font-mono);font-size:.68rem;letter-spacing:.08em;text-transform:uppercase;color:var(--fg3)}
.weather-days>li>:nth-child(2){font-family:var(--font-mono);color:var(--fg0);font-variant-numeric:tabular-nums}
.weather-days>li>:nth-child(3){overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.rain-cols{display:flex;align-items:flex-end;gap:1px;height:1rem}
.rain-cols>i{flex:1;height:var(--h,0%);min-height:1px;background:var(--cyan-n)}
/* Chart legend marks: last period (dashed outline), goal (dashed line), a highlighted window (e.g. the
   cheapest window), now (dashed upright). In the chart: .window, .now, and .bar-value above a bar
   (.is-in: inside it, on the series colour) */
.legend i.prev{background:none;border:1px dashed var(--c,var(--fg3))}
.legend i.goal{width:14px;height:0;vertical-align:3px;background:none;border-top:2px dashed var(--yellow)}
.legend i.goal.is-danger{border-top-color:var(--danger)}
.legend i.window{background:color-mix(in srgb,var(--c,var(--aqua)) 40%,transparent)}
.legend i.now{width:0;margin-inline:4px calc(.4rem + 4px);background:none;border-left:2px dashed var(--fg0)}
.chart .window{fill:color-mix(in srgb,var(--c,var(--aqua)) 22%,transparent);stroke:none}
.chart .now{stroke:var(--fg0);stroke-width:1;stroke-dasharray:3 3}
.chart .bar-value{fill:var(--fg1);font-weight:500;letter-spacing:0;text-anchor:middle;font-variant-numeric:tabular-nums}
.chart .bar-value.is-in{fill:var(--on-state)}
/* Drop zone: a tray that takes dragged items (tiles, files). .hint shows while it is empty;
   .is-armed while a drag is under way, .is-over while the item hovers it (like .drop) */
.dropzone{display:flex;flex-wrap:wrap;align-content:flex-start;gap:.6rem;min-height:4.5rem;padding:.8rem;background:var(--bg-hard);border:2px dashed var(--bg2)}
.dropzone>.hint{flex:1 1 100%;align-self:center;text-align:center;font-family:var(--font-mono);font-size:.68rem;letter-spacing:.12em;text-transform:uppercase;color:var(--fg3)}
.dropzone>.hint:not(:only-child){display:none}
.dropzone:has(>.hint:only-child){align-content:center}
.dropzone.is-armed{border-color:var(--cyan-n)}
.dropzone.is-over{border-color:var(--cyan);background:var(--cyan-tint)}
.dropzone.is-over>.hint{color:var(--cyan)}
@media(max-width:640px){
  .launch-grid[style*="--cols"]{grid-template-columns:repeat(auto-fill,minmax(min(var(--tile),100%),1fr))}
  .search>kbd{display:none}
}

/* ── Kante Light (apps, <html data-kante="light">) ─────────────────────
   Kante shapes on the platform look: controls get the system font, normal
   case and a small radius; cards keep the cut corner and the accent bar;
   titles stay Rajdhani, labels and figures JetBrains Mono. Colors come from
   the Breeze roles in tokens/variables.css (light or dark with the system). */
:root[data-kante="light"] .btn,:root[data-kante="light"] button.btn{--cut:0px;--grow:0px;font-family:var(--font-sans);font-weight:600;font-size:.95rem;letter-spacing:0;text-transform:none;border-radius:4px;padding:.5rem 1.1rem}
:root[data-kante="light"] .btn-accent{background:var(--primary);color:var(--on-primary)}
:root[data-kante="light"] .btn-accent:hover{background:var(--blue)}
:root[data-kante="light"] .btn-outline{--bw:1px;border-width:1px;border-color:var(--bg2);padding-block:calc(.5rem - 1px)}
:root[data-kante="light"] .input,:root[data-kante="light"] .select{font-family:var(--font-sans);font-size:.9rem;border-radius:4px}
:root[data-kante="light"] .seg{border-radius:4px;overflow:hidden}
:root[data-kante="light"] .seg button{font-family:var(--font-sans);font-size:.85rem;letter-spacing:0}
:root[data-kante="light"] .switch{font-family:var(--font-sans);font-size:.9rem;letter-spacing:0}
:root[data-kante="light"] .switch-track{border-radius:.6rem}
:root[data-kante="light"] .switch-track::after{border-radius:50%;background:var(--bg1)}
:root[data-kante="light"] .switch[aria-checked="true"] .switch-track::after{background:var(--on-primary)}
:root[data-kante="light"] .dialog h3,:root[data-kante="light"] .flow-node b{font-family:var(--font-sans);text-transform:none;letter-spacing:0;font-size:1.15rem}
:root[data-kante="light"] .tile,:root[data-kante="light"] .flow-node,:root[data-kante="light"] .dialog,:root[data-kante="light"] .toast{box-shadow:inset 0 0 0 1px var(--bg2)}
:root[data-kante="light"] .toolbar{background:var(--bg-panel);border-color:var(--bg2);border-radius:4px}
:root[data-kante="light"] .pill{border-radius:1rem}
/* Kante 1.13: the parts added since 1.5 follow the same rule (controls in the system font, normal case, small radius; card titles in the system font) */
:root[data-kante="light"] :is(.sheet>h3,.tier-card>h3,.tier-card>b,.status>.name,a.link-tile>.name,.launch-title,.editbar>.mode,.fold>summary,.empty b){font-family:var(--font-sans);text-transform:none;letter-spacing:0}
:root[data-kante="light"] .tabs{gap:0}
:root[data-kante="light"] .tabs :is(button,a),:root[data-kante="light"] .tabs-ind{clip-path:none;border-radius:4px 4px 0 0}
:root[data-kante="light"] :is(.tabs :is(button,a),.modebar>:is(button,a),.pager :is(a,button),.chip,.chip-pick,.toast>.toast-action){font-family:var(--font-sans);font-size:.85rem;letter-spacing:0;text-transform:none}
:root[data-kante="light"] :is(.modebar,.pager :is(a,button),.chip,.chip-pick,.toast>.toast-action,.combo-search>[role="listbox"],details.help>.help-text){border-radius:4px}
:root[data-kante="light"] .modebar{overflow:hidden}
:root[data-kante="light"] details.help>summary{border-radius:50%}

/* ── Thread: a conversation (Kintsugi's chat, Hansei's talk with the AI) ──
   .thread > .msg[data-from="ai"|"me"] > header (who, time) + text. The other side sits left
   with an info bar, the reader's own messages sit right with the primary bar. */
.thread{display:flex;flex-direction:column;gap:.7rem;min-width:0}
.msg{max-width:min(40rem,92%);padding:.6rem .85rem .7rem;background:var(--bg-panel);border-left:4px solid var(--bg2);font-size:.92rem;color:var(--fg1);overflow-wrap:anywhere}
.msg>header{display:flex;gap:.6rem;align-items:baseline;margin-bottom:.25rem;font-family:var(--font-mono);font-size:.64rem;letter-spacing:.12em;text-transform:uppercase;color:var(--fg3)}
.msg[data-from="ai"]{border-left-color:var(--info)}
.msg[data-from="me"]{align-self:flex-end;border-left:0;border-right:4px solid var(--primary);background:var(--tint-1)}
.msg[data-from="me"]>header{justify-content:flex-end}
.msg :is(p,ul,ol)+:is(p,ul,ol){margin-top:.5rem}
.msg :is(ul,ol){padding-left:1.2rem}

/* ── App page titles: the h1 of an app page and the heading of a block on it ── */
.page-title{font-family:var(--font-heading);font-weight:700;font-size:var(--title-l);line-height:1.02;text-transform:uppercase;letter-spacing:.02em;color:var(--fg0);text-wrap:balance}
.block-title{font-family:var(--font-heading);font-weight:700;font-size:var(--title-m);line-height:1.1;text-transform:uppercase;letter-spacing:var(--title-track);color:var(--fg0)}

/* ── Steps with state: .is-done ticks the number, aria-current="step" marks where you are;
   .steps.is-row lays a short process out in one line (setup wizards) ── */
.steps>li.is-done::before{content:"✓";background:var(--primary);border-color:var(--primary);color:var(--on-primary)}
.steps>li[aria-current="step"]{color:var(--fg0)}
.steps>li[aria-current="step"]::before{border-color:var(--primary);box-shadow:inset 0 0 0 1px var(--primary)}
.steps.is-row{display:flex;flex-wrap:wrap;gap:.6rem 2rem}
.steps.is-row>li{margin-bottom:0;line-height:1.8rem;font-family:var(--font-mono);font-size:.74rem;letter-spacing:.12em;text-transform:uppercase;color:var(--fg3)}
.steps.is-row>li:is(.is-done,[aria-current="step"]){color:var(--fg0)}

/* ── Nav: the current page ── */
.nav-links a[aria-current="page"]{color:var(--fg0);box-shadow:inset 0 -2px 0 var(--primary)}

/* ── App bar for phones: the main pages of an app as a bar at the bottom (Leuchtfeuer).
   .bottom-nav > a|button (icon + label), aria-current="page" marks the page; shown below 640px only,
   the normal tabs stay for wider screens. A last item can open more pages (details.dropdown with a .menu). ── */
.bottom-nav{display:none}
@media(max-width:640px){
  .bottom-nav{--safe-bottom:env(safe-area-inset-bottom,0px);position:fixed;left:0;right:0;bottom:0;z-index:30;display:flex;background:var(--bg-panel);border-top:2px solid var(--bg2);padding-bottom:var(--safe-bottom)}
  .bottom-nav>:is(a,button,details){flex:1 1 0;min-width:0}
  .bottom-nav :is(a,button,summary){display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.2rem;width:100%;min-height:var(--h-l);padding:.35rem .2rem;background:none;border:0;color:var(--fg3);cursor:pointer;text-decoration:none;
    font-family:var(--font-mono);font-size:.58rem;letter-spacing:.08em;text-transform:uppercase;list-style:none}
  .bottom-nav summary::-webkit-details-marker{display:none}
  .bottom-nav svg{width:20px;height:20px;fill:none;stroke:currentColor}
  .bottom-nav :is(a,button)[aria-current="page"]{color:var(--fg0);box-shadow:inset 0 2px 0 var(--primary)}
  .bottom-nav :is(a,button,summary):focus-visible{outline:2px solid var(--focus);outline-offset:-2px}
  .bottom-nav details.dropdown>.menu{top:auto;bottom:calc(100% + 4px);left:auto;right:0}
  :root:has(.bottom-nav) body{padding-bottom:calc(var(--h-l) + 1rem + env(safe-area-inset-bottom,0px))}
  :root:has(.bottom-nav) .toast-stack{bottom:calc(var(--h-l) + 1rem + var(--safe-bottom))}
  :root:has(.bottom-nav) .editbar.is-fixed{bottom:calc(var(--h-l) + env(safe-area-inset-bottom,0px))}
}

/* ── Help: a small "?" beside a label that opens a short explanation (term, unit, where to find a value).
   details.help > summary (the "?", aria-label) + .help-text. Opens on click or keyboard, closes on a second click. ── */
details.help{position:relative;display:inline-block;vertical-align:middle;margin-left:.3rem;text-transform:none;letter-spacing:0}
details.help>summary{display:inline-grid;place-items:center;width:var(--h-mark);height:var(--h-mark);border:1px solid var(--cyan);color:var(--cyan);font-family:var(--font-mono);font-size:.68rem;line-height:1;cursor:pointer;list-style:none}
details.help>summary::-webkit-details-marker{display:none}
details.help>summary:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
details.help[open]>summary{background:var(--cyan-tint)}
details.help>.help-text{position:absolute;z-index:25;top:calc(100% + 6px);left:-.5rem;width:max-content;max-width:min(20rem,80vw);background:var(--bg-panel);border-top:2px solid var(--cyan);padding:.6rem .8rem;
  font-family:var(--font-sans);font-size:.82rem;line-height:1.4;color:var(--fg1);border-inline:1px solid var(--bg2);border-bottom:1px solid var(--bg2)}
details.help.is-right>.help-text{left:auto;right:-.5rem}

/* ── Toast with an action, e.g. "Undo" after a delete: .toast > .toast-action (a quiet button) ── */
.toast>.toast-action{margin-left:auto;flex:none;display:inline-flex;align-items:center;min-height:var(--h-xs);background:none;border:1px solid currentColor;color:var(--fg0);padding:0 .6rem;cursor:pointer;
  font-family:var(--font-mono);font-size:.68rem;letter-spacing:.1em;text-transform:uppercase}
.toast>.toast-action:hover{background:var(--cyan-tint)}
.toast>.toast-action:focus-visible{outline:2px solid var(--focus);outline-offset:2px}

/* ── Ring picker: one of N marks on a circle, e.g. the start LED of a light ring or a dial position.
   .ring-pick (--n marks, default 12; --r radius) > button[role="radio"][aria-checked][style="--i:k"] for k = 0…n-1,
   mark 0 at the top, clockwise; .ring-pick-n shows the value in the middle. Markers are squares (Kante rule). ── */
.ring-pick{--n:12;--r:4.1rem;position:relative;width:calc(var(--r) * 2 + 2rem);aspect-ratio:1;margin:.3rem 0}
.ring-pick>button{position:absolute;left:calc(50% - .65rem);top:calc(50% - .65rem);width:1.3rem;height:1.3rem;padding:0;border:2px solid var(--fg3);background:var(--bg-hard);cursor:pointer;
  transform:rotate(calc(var(--i) * 360deg / var(--n))) translateY(calc(var(--r) * -1))}
.ring-pick>button:hover{border-color:var(--fg0)}
.ring-pick>button[aria-checked="true"]{background:var(--primary);border-color:var(--primary)}
.ring-pick>button:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
.ring-pick>.ring-pick-n{position:absolute;inset:0;display:grid;place-items:center;font-family:var(--font-mono);font-size:1.4rem;color:var(--fg2);pointer-events:none}

/* ── Touch: chips get the small control height, so a finger hits them ── */
@media (pointer:coarse){.chip{height:var(--h-s)}.chip-pick{min-height:var(--h-s)}}
/* Touch: also the language toggle, switches and the help "?" reach the control height --h-s (the "?" keeps its look and
   gets a larger hit area instead) */
@media (pointer:coarse){.lang button,.switch{min-height:var(--h-s)}details.help>summary{position:relative}details.help>summary::before{content:"";position:absolute;inset:-6px}}

/* ── Keyboard focus on segments and switches (they had none) ── */
.seg button:focus-visible{outline:2px solid var(--focus);outline-offset:-2px}
.switch:focus-visible{outline:2px solid var(--focus);outline-offset:2px}

/* ── Board card: a board as a card with a floor plan of its tiles.
   .board-grid > .board-card[.is-start][.is-off] > .grip, .plan > div[--cols] > i[--w,--h,data-tier], .board-body
   (.board-name, .board-meta, .board-foot); .board-add is the dashed "new board" card ── */
.board-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(18rem,100%),1fr));gap:1rem}
.board-card{position:relative;display:flex;flex-direction:column;background:var(--bg-panel);border:1px solid var(--bg1);border-top:4px solid var(--bg2);
  clip-path:polygon(0 0,calc(100% - var(--cut-m)) 0,100% var(--cut-m),100% 100%,0 100%)}
.board-card:hover,.board-card:focus-within{border-top-color:var(--hl)}
/* An open menu leaves the card: drop the cut while it is open */
.board-card:has(details[open]){clip-path:none;z-index:2}
.board-card.is-start{border-top-color:var(--primary)}
.board-card.is-off :is(.plan,.board-name){opacity:.5}
.board-card>.grip{position:absolute;top:.9rem;left:.6rem;z-index:1}
.board-card>.grip~.plan{padding-left:1.8rem}
.board-card.sortable-ghost{opacity:.4}
.plan{display:flex;flex-direction:column;gap:6px;height:6.6rem;overflow:hidden;padding:.9rem;background:var(--bg-hard)}
.plan>div{display:grid;grid-template-columns:repeat(var(--cols,6),minmax(0,1fr));grid-auto-rows:.55rem;gap:3px}
.plan>div+div{padding-top:6px;border-top:2px solid var(--bg1)}
.plan i{grid-column:span var(--w,1);grid-row:span var(--h,1);background:var(--bg2)}
.plan i[data-tier="yellow"]{background:var(--warn)}
.plan i[data-tier="red"]{background:var(--danger)}
.plan i[data-tier="cyan"],.plan i[data-tier="blue"]{background:var(--cyan-n)}
.board-body{display:flex;flex-direction:column;gap:.45rem;flex:1;padding:.8rem .9rem .9rem}
.board-name{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;min-width:0}
.board-name>a{font-family:var(--font-heading);font-weight:700;font-size:1.35rem;line-height:1.15;color:var(--fg0);text-decoration:none;overflow-wrap:anywhere}
.board-name>a:hover{color:var(--hl)}
.board-meta{display:flex;flex-wrap:wrap;gap:.2rem .8rem;font-family:var(--font-mono);font-size:.7rem;color:var(--fg3);font-variant-numeric:tabular-nums}
.board-meta .is-warn{color:var(--warn-text)}
.board-foot{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;margin-top:auto;padding-top:.55rem;border-top:1px solid var(--bg1)}
.board-foot>form{display:contents}
.board-foot>.switch,.board-foot>form:first-child>.switch{margin-right:auto}
.board-add{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:.3rem;min-height:14rem;border:1px dashed var(--bg2);
  color:var(--fg3);font-family:var(--font-heading);font-weight:600;font-size:1.1rem;text-transform:uppercase;text-decoration:none}
.board-add:hover{border-color:var(--hl);color:var(--fg0);text-decoration:none}
.board-add>b{font-size:2rem;line-height:1;color:var(--fg2)}

/* ── A field in a menu, e.g. a target picker above its button ── */
.menu :is(.select,.input){display:block;width:calc(100% - 1.8rem);margin:.3rem .9rem}

/* ── Screen-reader only: a label that is read out but not shown (e.g. a column of number fields with a visible head) ── */
.sr-only{position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* ── Seam (Kante Gold, from Kintsugi): the gold seam, a drawn line that mends a break.
   Divider under the nav (.nav > .seam) and under titles (.seam.is-short). Drawn in --yellow. */
.seam{display:block;height:8px;background:var(--yellow);pointer-events:none;
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='8'%3E%3Cpath d='M0 4 L20 3 L38 5 L60 2 L84 5 L104 4 L128 6 L150 3 L172 5 L196 2 L218 5 L240 4' fill='none' stroke='black' stroke-width='1.3' stroke-linecap='round'/%3E%3C/svg%3E") repeat-x 0 50%/240px 8px;mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='8'%3E%3Cpath d='M0 4 L20 3 L38 5 L60 2 L84 5 L104 4 L128 6 L150 3 L172 5 L196 2 L218 5 L240 4' fill='none' stroke='black' stroke-width='1.3' stroke-linecap='round'/%3E%3C/svg%3E") repeat-x 0 50%/240px 8px}
.seam.is-short{width:2.5rem}
.nav>.seam{position:absolute;left:0;right:0;bottom:-4px;opacity:.85}

/* ── Kante Gold (<html data-kante="gold">) ───────────────────────────
   The noble variant, only for Kintsugi. Colours, fonts and motion values are in
   tokens/variables.css; here the details: serif titles with tracked capitals (controls stay
   Rajdhani via --font-control), 2 px bars, gold hairlines, a gold line on every cut edge,
   a shimmer instead of hazard stripes, and the crackle ground behind the page. */
:root[data-kante="gold"] :is(.page-title,.block-title,.nav-brand,.hero h1,.install-card label,.fact b,.showcase h2,.flow-node b,.faq summary,.feat h3,.section h2,.steps>li::before,.banner-title,.foot-name,.dialog h3,.table tfoot td,.kpi>b,.bulk-bar>.n,.sheet>h3,.status>.name,a.link-tile>.name,.fold>summary,.tier-card>h3,.tier-card>b,.date-tile>b,.editbar>.mode,.login>.brand,.login>h1,.contrast>.sample,.launch-icon>.monogram,.launch-title,.clock-zone>strong,.weather>b){font-weight:500;letter-spacing:.06em}
:root[data-kante="gold"] :is(.kpi>b,.fact b,.bulk-bar>.n,.date-tile>b,.clock-zone>strong,.weather>b,.steps>li::before){letter-spacing:.01em;font-variant-numeric:lining-nums tabular-nums}
:root[data-kante="gold"] :is(.nav-brand,.login>.brand,.foot-name){letter-spacing:.3em}
:root[data-kante="gold"] .table th{font-family:var(--font-mono);font-weight:500;font-size:.68rem;letter-spacing:.16em;color:var(--fg2)}
:root[data-kante="gold"] .btn{font-weight:600}
:root[data-kante="gold"] .feat-icon{stroke-width:1.5}
/* Less weight: 2 px bars, gold hairlines */
:root[data-kante="gold"] :is(.flow-node,.faq details,.feat,.callout,.band,.toast,.dialog,.sheet,.status,.palette,a.link-tile,.launch,.tier-card,.hint-card,.login,.tile,.option,.editbar,.bulk-bar,.detail-card){border-top-width:var(--bar)}
:root[data-kante="gold"] .timeline>li{border-left-width:var(--bar)}
:root[data-kante="gold"] .option{border-color:var(--gold-line)}
:root[data-kante="gold"] .feat::before{top:calc(-1 * var(--bar));height:var(--bar)}
:root[data-kante="gold"] .msg{border-left-width:var(--bar)}
:root[data-kante="gold"] .msg[data-from="me"]{border-right-width:var(--bar)}
:root[data-kante="gold"] :is(.table-wrap,.codeblock,.modebar,.toolbar,.empty){border-color:var(--gold-line)}
:root[data-kante="gold"] .modebar>:is(button,a){border-right-color:var(--gold-line)}
:root[data-kante="gold"] .table td{border-top-color:color-mix(in srgb,var(--yellow) 12%,transparent)}
:root[data-kante="gold"] .btn-outline{--bw:1px;--bc:var(--gold-line)}
:root[data-kante="gold"] .btn-outline:hover{--bc:var(--yellow);background-color:var(--bg1)}
:root[data-kante="gold"] .tabs{border-bottom-width:1px;border-bottom-color:var(--gold-line)}
:root[data-kante="gold"] .tabs :is(button,a){background:transparent}
:root[data-kante="gold"] .tabs :is(button,a):is([aria-selected="true"],[aria-current="page"]){background:transparent;color:var(--yellow);box-shadow:inset 0 -2px 0 var(--yellow)}
:root[data-kante="gold"] .tabs :is(button,a):is([aria-selected="true"],[aria-current="page"]) .count{background:var(--yellow);color:var(--on-primary)}
/* The sliding indicator (shrippen.js) is the 2 px gold underline, not a fill */
:root[data-kante="gold"] .tabs-ind{top:auto;height:2px;clip-path:none}
:root[data-kante="gold"] .tabs.has-ind :is(button,a):is([aria-selected="true"],[aria-current="page"]){box-shadow:none}
/* The gilded edge: a gold line along the cut of every surface */
:root[data-kante="gold"] :is(.ch,.feat:not(a),.callout,.codeblock,.table-wrap,.flow-node,.faq details,.dialog,.sheet,.palette,.login){--gc:var(--chamfer)}
:root[data-kante="gold"] :is(.status,.tier-card,.hint-card,.menu,.bulk-bar,.launch,a.link-tile,.option,.editbar:not(.has-menu),.toast){--gc:var(--cut-m)}
:root[data-kante="gold"] :is(.ch,.feat:not(a),.callout,.codeblock,.table-wrap,.flow-node,.faq details,.dialog,.sheet,.palette,.login,.status,.tier-card,.hint-card,.menu,.bulk-bar,.launch,a.link-tile,.option,.editbar:not(.has-menu),.toast){
  background-image:linear-gradient(to bottom left,transparent calc(50% - var(--gild) / 2),var(--yellow) calc(50% - var(--gild) / 2),var(--yellow) calc(50% + var(--gild) / 2),transparent calc(50% + var(--gild) / 2));
  background-repeat:no-repeat;background-position:top right;background-size:var(--gc) var(--gc);background-origin:border-box}
/* The drawer's cut sits top left: its gilded edge too */
:root[data-kante="gold"] .sheet.is-drawer{
  background-image:linear-gradient(to bottom right,transparent calc(50% - var(--gild) / 2),var(--yellow) calc(50% - var(--gild) / 2),var(--yellow) calc(50% + var(--gild) / 2),transparent calc(50% + var(--gild) / 2));
  background-position:top left}
/* Busy: a slow shimmer instead of marching hazard stripes */
:root[data-kante="gold"] .progress-bar.is-indeterminate{background:linear-gradient(90deg,var(--bg-hard) 0 30%,var(--yellow) 50%,var(--bg-hard) 70%) 0 0/250% 100%}
:root[data-kante="gold"] .btn.is-busy{background-image:linear-gradient(90deg,var(--primary) 0 30%,var(--yellow-hi) 50%,var(--primary) 70%);background-size:250% 100%}
:root[data-kante="gold"] .btn-outline.is-busy{background-image:linear-gradient(90deg,transparent 0 30%,var(--tint-2) 50%,transparent 70%);background-size:250% 100%;background-position:0 0}
:root[data-kante="gold"] .banner::before,:root[data-kante="gold"] .banner::after{height:var(--bar);background:var(--accent)}
/* Crackle ground: Kintsugi's breaks in gold, very quiet, behind the whole page */
:root[data-kante="gold"] body::before{content:"";position:fixed;top:-50%;left:-50%;width:200%;height:200%;z-index:-1;pointer-events:none;contain:strict;
  background:var(--yellow);opacity:.05;-webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='480' height='480'%3E%3Cg fill='none' stroke='black' stroke-width='1.4' stroke-linecap='round'%3E%3Cpath d='M-20 60 L60 90 L110 40 L180 110 L260 70 L340 150 L420 90 L500 140'/%3E%3Cpath d='M0 260 L70 230 L140 300 L210 240 L300 310 L380 250 L460 320 L500 280'/%3E%3Cpath d='M40 -10 L90 60 L60 140 L120 200 L90 280 L150 350 L120 430 L160 500'/%3E%3Cpath d='M340 -10 L300 70 L360 130 L320 210 L380 270 L340 350 L400 420 L360 500'/%3E%3C/g%3E%3C/svg%3E") repeat 0 0/480px 480px;mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='480' height='480'%3E%3Cg fill='none' stroke='black' stroke-width='1.4' stroke-linecap='round'%3E%3Cpath d='M-20 60 L60 90 L110 40 L180 110 L260 70 L340 150 L420 90 L500 140'/%3E%3Cpath d='M0 260 L70 230 L140 300 L210 240 L300 310 L380 250 L460 320 L500 280'/%3E%3Cpath d='M40 -10 L90 60 L60 140 L120 200 L90 280 L150 350 L120 430 L160 500'/%3E%3Cpath d='M340 -10 L300 70 L360 130 L320 210 L380 270 L340 350 L400 420 L360 500'/%3E%3C/g%3E%3C/svg%3E") repeat 0 0/480px 480px}

/* ── Kante 1.19: phone layouts ─────────────────────────────────────────
   Filter side, compact hint rows, nav drawer, tables as cards. Below 640px a page starts with its
   content: filters and navigation fold behind a button, table rows become cards. */
/* Filter side: the filters of a long list in a column left of it, one entry per value with its count.
   <div class="filter-layout"><aside class="filter-side" id="f">[.search]<span class="h-label">Level</span>
   <ul class="filter-list"><li><a href="…" aria-current="true">All <small>165</small></a></li>…
   <li><details><summary>show all 12</summary><ul class="filter-list">…</ul></details></li></ul></aside>
   <div class="filter-main"><div class="filter-head"><button class="btn btn-outline btn-sm filter-toggle" aria-controls="f" aria-expanded="false">Filter (1)</button>…</div>…list…</div></div>
   Below 640px the side hides behind .filter-toggle (shrippen.js flips aria-expanded) and opens as a panel under the head. */
.filter-layout{display:grid;grid-template-columns:minmax(11rem,13rem) minmax(0,1fr);gap:1.6rem;align-items:start}
.filter-side{position:sticky;top:1rem;display:flex;flex-direction:column;gap:.5rem;min-width:0}
.filter-side>.h-label{margin:.6rem 0 0}
.filter-side>.search{flex:none}
.filter-list{display:flex;flex-direction:column;gap:1px;margin:0;padding:0;list-style:none}
.filter-list :is(a,button){display:flex;align-items:center;justify-content:space-between;gap:.6rem;width:100%;min-height:var(--h-s);padding-inline:.7rem;background:none;border:0;
  color:var(--fg2);font:inherit;font-size:.86rem;text-align:start;text-decoration:none;cursor:pointer}
.filter-list :is(a,button)>small{flex:none;font-family:var(--font-mono);font-size:.68rem;color:var(--fg3);font-variant-numeric:tabular-nums}
.filter-list :is(a,button):hover{background:var(--tint-1);color:var(--fg0);text-decoration:none}
.filter-list :is(a,button):is([aria-current="true"],[aria-current="page"],[aria-pressed="true"]),
.filter-list :is(a,button):is([aria-current="true"],[aria-current="page"],[aria-pressed="true"])>small{background:var(--cyan-tint);color:var(--cyan)}
.filter-list :is(a,button):is([aria-current="true"],[aria-current="page"],[aria-pressed="true"]){box-shadow:inset 3px 0 0 var(--cyan)}
.filter-list :is(a,button):focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--focus)}
.filter-list details>summary{display:flex;align-items:center;min-height:var(--h-s);padding-inline:.7rem;cursor:pointer;list-style:none;font-family:var(--font-mono);font-size:.7rem;letter-spacing:.06em;color:var(--link)}
.filter-list details>summary::-webkit-details-marker{display:none}
.filter-list details[open]>summary{display:none}
.filter-list details>summary:focus-visible{outline:2px solid var(--focus);outline-offset:-2px}
.filter-main{display:flex;flex-direction:column;gap:1rem;min-width:0}
.filter-head{display:flex;flex-wrap:wrap;align-items:center;gap:.6rem}
.filter-head>*{margin:0}
.filter-head>.grow{flex:1}
.filter-toggle.filter-toggle{display:none}
/* Compact hint row: one line per hint, the tier as its shape only (the word stays for screen readers),
   title with a meta line under it, one primary action. A <details> in .actions takes the full row when open.
   <li class="hint-card is-row" data-tier="red"><span class="tier"><span class="sr-only">Critical</span></span>
   <div class="row-main"><span class="title">…</span><span class="meta">Kimai · 3 d</span></div><div class="actions">…</div></li> */
.hint-card.is-row{flex-direction:row;flex-wrap:wrap;align-items:center;column-gap:.7rem;padding:.45rem .6rem .45rem .8rem;border-top:0;box-shadow:inset 3px 0 0 var(--tier)}
.hint-card.is-row>.tier{flex:none}
.hint-card.is-row>.row-main{flex:1 1 0;min-width:0;display:flex;flex-direction:column;gap:.1rem}
.hint-card.is-row>.row-main>.title{color:var(--fg0);font-weight:600;font-size:.9rem;line-height:1.3;overflow-wrap:anywhere}
.hint-card.is-row>.row-main>.meta{font-family:var(--font-mono);font-size:.66rem;letter-spacing:.04em;color:var(--fg3)}
.hint-card.is-row>.actions{flex:none;margin:0;flex-wrap:nowrap}
.hint-card.is-row>.actions:has(>details[open]){flex:1 1 100%;flex-wrap:wrap}
.hint-card.is-row>.actions>details[open]{flex:1 1 100%;order:1}
.hint-card.is-row>.actions>details>summary{list-style:none;cursor:pointer;padding:0 .3rem;font-family:var(--font-mono);color:var(--fg3)}
.hint-card.is-row>.actions>details>summary::-webkit-details-marker{display:none}
.hint-card.is-row>.actions>details>summary:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
/* Nav drawer: below 640px the nav keeps logo, a counter, search and a menu button (.nav-burger); its
   pages open from the left in a modal <dialog class="nav-drawer"> (shrippen.js: open, close on Esc,
   scrim or [data-drawer-close], focus back to the button, aria-expanded). .nav-wide marks what the
   drawer replaces on phones, .nav-narrow what shows only there.
   <button class="nav-burger" aria-controls="menu" aria-expanded="false" aria-label="Menu"><svg…></button>
   <dialog class="nav-drawer" id="menu"><div class="nav-drawer-head">brand <button data-drawer-close>×</button></div>
   <nav class="nav-drawer-list"><span class="h-label">Pages</span><a aria-current="page">Hints <span class="count">3</span></a>…</nav></dialog> */
.nav-burger{display:none;place-items:center;flex:none;width:var(--h-m);height:var(--h-m);margin:0;padding:0;background:none;border:1px solid var(--bg2);color:var(--fg1);cursor:pointer}
.nav-burger:hover{background:var(--tint-1);color:var(--fg0)}
.nav-burger:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
.nav-burger svg{width:20px;height:20px;fill:none;stroke:currentColor;stroke-width:2}
.nav-drawer{position:fixed;top:0;bottom:0;left:0;right:auto;margin:0;padding:0;width:min(20rem,calc(100vw - 3rem));max-width:none;height:100dvh;max-height:none;
  display:flex;flex-direction:column;overflow-y:auto;overscroll-behavior:contain;background:var(--bg-panel);color:var(--fg1);border:0;border-right:4px solid var(--yellow)}
.nav-drawer:not([open]){display:none}
.nav-drawer::backdrop{background:var(--scrim)}
.nav-drawer-head{display:flex;align-items:center;justify-content:space-between;gap:.6rem;min-height:3.25rem;padding:0 .5rem 0 1rem;border-bottom:1px solid var(--bg1)}
.nav-drawer-head>.btn{margin:0}
.nav-drawer-list{display:flex;flex-direction:column;padding-bottom:1rem}
.nav-drawer-list>.h-label{margin:1rem 1rem .3rem;border-bottom:0;padding-bottom:0}
.nav-drawer-list form{margin:0}
.nav-drawer-list :is(a,button):not(.btn){display:flex;align-items:center;gap:.6rem;width:100%;min-height:var(--h-m);padding:0 1rem;background:none;border:0;margin:0;
  color:var(--fg1);font:inherit;font-size:.95rem;text-align:start;text-decoration:none;cursor:pointer}
.nav-drawer-list :is(a,button):not(.btn)>.count{margin-left:auto}
.nav-drawer-list :is(a,button):not(.btn):hover{background:var(--tint-1);color:var(--fg0)}
.nav-drawer-list a[aria-current="page"]{background:var(--cyan-tint);color:var(--fg0);box-shadow:inset 3px 0 0 var(--cyan)}
.nav-drawer-list :is(a,button):not(.btn):focus-visible{outline:none;box-shadow:inset 0 0 0 2px var(--focus)}
.nav-drawer-list hr{border:0;border-top:1px solid var(--bg1);margin:.5rem 0}
/* .nav-narrow is the counterpart of .nav-wide: shown only below 640px (e.g. the hint counter beside the brand) */
.nav-narrow{display:none}
/* Table as cards: <table class="table cards-sm">, each <td data-label="Column"> (the header text).
   Below 640px every row is a card: the first cell (or data-card="title") its title, the cell with
   data-card="key" (an amount) top right in mono, the other cells a label/value list; cells without
   data-label (actions) span the card. The header row stays for screen readers. */
@media(max-width:640px){
  .table-wrap:has(>.table.cards-sm){border:0;background:none;clip-path:none;overflow:visible}
  .table.cards-sm,.table.cards-sm>:is(tbody,tfoot){display:block}
  .table.cards-sm>thead,.table.cards-sm tr:has(>th){position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
  .table.cards-sm tr{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:.25rem .8rem;margin-bottom:.5rem;padding:.65rem .8rem .7rem;background:var(--bg-panel);border:1px solid var(--bg1);
    clip-path:polygon(0 0,calc(100% - var(--cut-m)) 0,100% var(--cut-m),100% 100%,0 100%)}
  .table.cards-sm td{display:block;grid-column:1/-1;padding:0;border:0;text-align:start;overflow-wrap:anywhere}
  .table.cards-sm td:empty{display:none}
  .table.cards-sm td[data-label]{position:relative;padding-left:min(42%,9rem);min-height:1.2rem}
  .table.cards-sm td[data-label]::before{content:attr(data-label);position:absolute;left:0;top:.15em;width:calc(min(42%,9rem) - .6rem);text-align:start;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
    font-family:var(--font-mono);font-size:.62rem;letter-spacing:.1em;text-transform:uppercase;color:var(--fg3)}
  .table.cards-sm td.num{font-family:var(--font-mono);text-align:start;white-space:normal}
  .table.cards-sm :is(td[data-card="title"],tr:not(:has(>[data-card="title"]))>td:first-child){grid-row:1;grid-column:1;padding-left:0;color:var(--fg0);font-weight:600}
  .table.cards-sm td[data-card="key"]{grid-row:1;grid-column:2;padding-left:0;text-align:end;font-family:var(--font-mono);font-variant-numeric:tabular-nums;color:var(--fg0);white-space:nowrap}
  .table.cards-sm :is(td[data-card="title"],td[data-card="key"],tr:not(:has(>[data-card="title"]))>td:first-child)::before{content:none}
  /* The key names its column above the value, small (a card shows one figure top right; without the name "7.315 €" could be anything) */
  .table.cards-sm tr>td[data-card="key"][data-label]::before{content:attr(data-label);position:static;display:block;width:auto;margin-bottom:.1rem;font-family:var(--font-mono);font-size:.6rem;font-weight:400;letter-spacing:.1em;text-transform:uppercase;color:var(--fg3);text-align:end}
  .table.cards-sm tr:not(:has(>[data-card="key"])):not(:has(>[data-card="title"]))>td:first-child,
  .table.cards-sm tr:not(:has(>[data-card="key"]))>td[data-card="title"]{grid-column:1/-1}
  .table.cards-sm .group-row{grid-template-columns:minmax(0,1fr);padding:.4rem .8rem;clip-path:none}
  .table.cards-sm tfoot tr{border-top:2px solid var(--yellow)}
  /* The filter side folds behind its button; the head comes first, the open panel under it */
  .filter-layout{grid-template-columns:minmax(0,1fr);gap:.8rem}
  .filter-main{display:contents}
  .filter-head{order:-1}
  .filter-main>:not(.filter-head){order:1}
  .filter-side{display:none;position:static;padding:.8rem;background:var(--bg-panel);border-top:4px solid var(--cyan)}
  .filter-layout:has(.filter-toggle[aria-expanded="true"])>.filter-side{display:flex}
  .filter-toggle.filter-toggle{display:inline-flex}
  /* A button with a long label (e.g. "Create draft for <client>") wraps instead of widening the page */
  .btn{max-width:100%;white-space:normal;text-align:center}
  /* The nav drawer replaces the wide nav */
  .nav-burger{display:inline-grid}
  .nav-wide{display:none!important}
  .nav-narrow{display:revert}
}
@media(min-width:641px){.nav-drawer{display:none}}

/* ── Mobile ── */
@media(max-width:900px){
  .showcase,.showcase.rev{grid-template-columns:minmax(0,1fr);gap:1.6rem}
  .showcase.rev>figure{order:0}
  .flow{flex-direction:column}
  .flow-arrow{flex:0 0 1.6rem}
  .flow-arrow::before{content:"↓"}
  .hero{grid-template-columns:minmax(0,1fr);gap:2rem;align-items:start}
  .hero-side{padding-bottom:0}
  /* One column has the full width: write the name out and size it to the longest word */
  .hero h1{font-size:var(--title-size-narrow,clamp(3rem,22vw,13.1rem))}
  .hero h1 br.split{display:none}
  .hero>.hero-wm{width:90vw;right:-25vw;top:0}
}
@media(max-width:640px){
  .bands{grid-template-columns:minmax(0,1fr)}
  .setting{grid-template-columns:minmax(0,1fr)}
  .setting>.ctl{grid-column:1;grid-row:auto;flex-wrap:wrap}
  .bulk-bar{flex-wrap:nowrap;overflow-x:auto;gap:.5rem}
  .bulk-bar>*{flex:none}
  .editbar>.mode{flex:1 0 100%}
  .editbar>.btn{flex:1 1 0;padding-inline:.3rem}
  .editbar>.grow{display:none}
  .share>.row{grid-template-columns:minmax(0,1fr) auto}
  .share>.row>.select{grid-column:1;grid-row:2}
  .login-code{--cell:2.4rem;--gap:.35rem;font-size:1.45rem}
  .toolbar-sep{display:none}
  .nav-inner.is-wrap .nav-links a{display:inline}
  .nav-links a{display:none}
  .install-card{padding:1.25rem 1.2rem 1.4rem}
  .cmd-box{font-size:.75rem}
  .foot-brand img{width:64px;height:64px}
  .foot-cols{gap:2rem}
}
/* Topic icon: one line icon per tile group (data-topic), drawn in the text colour; it follows font-size */
.topic-icon{display:inline-block;flex:none;width:1.1em;height:1.1em;vertical-align:-.2em;background:currentColor;-webkit-mask:var(--topic-icon) center/contain no-repeat;mask:var(--topic-icon) center/contain no-repeat}
.topic-icon[data-topic="overview"]{--topic-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' fill='none'%3E%3Crect x='3' y='3' width='7' height='7' rx='1.5'/%3E%3Crect x='14' y='3' width='7' height='7' rx='1.5'/%3E%3Crect x='3' y='14' width='7' height='7' rx='1.5'/%3E%3Crect x='14' y='14' width='7' height='7' rx='1.5'/%3E%3C/svg%3E")}
.topic-icon[data-topic="work"]{--topic-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' fill='none'%3E%3Crect x='3' y='7' width='18' height='13' rx='2'/%3E%3Cpath d='M9 7V5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2M3 13h18'/%3E%3C/svg%3E")}
.topic-icon[data-topic="analysis"]{--topic-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' fill='none'%3E%3Cpath d='M4 20h16M7 17v-5M12 17V6M17 17v-8'/%3E%3C/svg%3E")}
.topic-icon[data-topic="homelab"]{--topic-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' fill='none'%3E%3Crect x='3' y='4' width='18' height='7' rx='2'/%3E%3Crect x='3' y='13' width='18' height='7' rx='2'/%3E%3Cpath d='M7 7.5h.01M7 16.5h.01'/%3E%3C/svg%3E")}
.topic-icon[data-topic="network"]{--topic-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' fill='none'%3E%3Ccircle cx='12' cy='5' r='2.5'/%3E%3Ccircle cx='5' cy='19' r='2.5'/%3E%3Ccircle cx='19' cy='19' r='2.5'/%3E%3Cpath d='M12 7.5v4M12 11.5l-6 5M12 11.5l6 5'/%3E%3C/svg%3E")}
.topic-icon[data-topic="security"]{--topic-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' fill='none'%3E%3Cpath d='M12 3l8 3v6c0 5-3.5 8-8 9-4.5-1-8-4-8-9V6z'/%3E%3Cpath d='M9 12l2 2 4-4'/%3E%3C/svg%3E")}
.topic-icon[data-topic="media"]{--topic-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' fill='none'%3E%3Crect x='3' y='5' width='18' height='14' rx='3'/%3E%3Cpath d='M10 9.5v5l4.5-2.5z'/%3E%3C/svg%3E")}
.topic-icon[data-topic="home"]{--topic-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' fill='none'%3E%3Cpath d='M3 11l9-8 9 8M5 10v10h14V10M10 20v-6h4v6'/%3E%3C/svg%3E")}
.topic-icon[data-topic="world"]{--topic-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' fill='none'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M3 12h18M12 3c3 3 3 15 0 18-3-3-3-15 0-18'/%3E%3C/svg%3E")}
.topic-icon[data-topic="dev"]{--topic-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' fill='none'%3E%3Cpath d='M8 8l-4 4 4 4M16 8l4 4-4 4M13.5 5l-3 14'/%3E%3C/svg%3E")}
.topic-icon[data-topic="links"]{--topic-icon:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' fill='none'%3E%3Cpath d='M10 14a4 4 0 0 0 5.7 0l3-3a4 4 0 0 0-5.7-5.7l-1 1M14 10a4 4 0 0 0-5.7 0l-3 3a4 4 0 0 0 5.7 5.7l1-1'/%3E%3C/svg%3E")}

/* ── Wall display (1.20): a stage that shows one screen-filling set of tiles at a time and
   switches between sets with a transition from js/kante-wall.js.
     .wall-stage            .is-screen: the whole screen, no scrolling; .is-preview: a 16:9 preview
       > .wall-set          one set; the next set comes after the shown one (on top)
                            .is-fit scales the set's children by --wall-scale (a set taller than the stage)
       > .wall-blade        the yellow blade of the cut, .wall-scan the line of the scan (added by a transition)
       > .wall-progress > i time left of the set (--wall-time, runs only with motion)
       > .wall-pager > i    one square per set, .is-on the shown one
   [data-wall-off] hides a tile or a section outside the shown set.
   .wall-tiles > .wall-tile (b name, small kind; --tier) are placeholder tiles for a preview. */
.wall-stage{position:relative;overflow:hidden;container-type:inline-size}
.wall-stage.is-screen{position:fixed;inset:0}
.wall-stage.is-preview{aspect-ratio:16/9;width:100%;border:4px solid var(--bg2);background:var(--bg-void)}
.wall-set{position:absolute;inset:0;overflow:hidden;background:var(--bg-void)}
.wall-set[hidden]{display:none}
.wall-set.is-fit>*{transform:scale(var(--wall-scale,1));transform-origin:top center}
[data-wall-off]{display:none!important}
.wall-blade{position:absolute;top:-10%;bottom:-10%;left:-12%;width:1cqw;background:var(--primary);transform:skewX(-24deg);pointer-events:none;z-index:5}
.wall-scan{position:absolute;left:0;right:0;top:0;height:.35cqw;background:var(--cyan);box-shadow:0 0 2cqw var(--cyan);pointer-events:none;z-index:5}
.wall-progress{position:absolute;left:0;right:0;bottom:0;height:4px;z-index:6;pointer-events:none}
.wall-progress>i{display:block;height:100%;background:var(--primary);transform-origin:left;transform:scaleX(0)}
.wall-pager{position:absolute;right:1rem;bottom:.9rem;display:flex;gap:.4rem;z-index:6;pointer-events:none}
.wall-pager>i{width:.7rem;height:.7rem;border:1px solid var(--fg3)}
.wall-pager>i.is-on{background:var(--primary);border-color:var(--primary)}
.wall-tiles{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));grid-auto-rows:minmax(0,1fr);gap:1cqw;padding:1.4cqw;height:100%}
.wall-tile{background:var(--bg-panel);border-top:.35cqw solid var(--tier,var(--bg2));padding:1cqw 1.2cqw;display:flex;flex-direction:column;gap:.5cqw;min-width:0;overflow:hidden}
.wall-tile>b{font-family:var(--font-heading);font-size:2.2cqw;line-height:1.05;color:var(--fg0);text-transform:uppercase;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wall-tile>small{font-family:var(--font-mono);font-size:1cqw;letter-spacing:.12em;text-transform:uppercase;color:var(--fg3);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ── Kante 1.25: spoken conversation (Kaiwa). QML twins: KanteRubyText, KanteHeardLine,
   KanteTalkButton, KanteDiffText, KanteHintCard, KantePitchCurve, KantePath, KanteGoalMeter.
   Catalogue: proposals/2026-10-kaiwa/. ── */
/* Ruby text: <p class="ruby" data-ruby="all|new|none"><ruby>駅<rt>えき</rt></ruby>…</p>; ruby.is-new marks
   a new word for data-ruby="new". The room for the readings stays, so switching never moves the lines.
   Readings stay muted, new words too (D-1). */
.ruby{line-height:2.3}
.ruby rt{font-family:var(--font-sans);font-size:.5em;letter-spacing:.04em;color:var(--fg3)}
.ruby[data-ruby="none"] rt,.ruby[data-ruby="new"] ruby:not(.is-new) rt{visibility:hidden}
/* Heard as: under your own .msg, what the recogniser heard; data-state="unsure" warns with the word, and a link
   "misheard" keeps the turn out. <div class="heard" data-state="unsure"><b>unsicher</b> · … <a href="#">falsch erkannt</a></div> */
.heard{font-family:var(--font-mono);font-size:.7rem;color:var(--fg3);margin-top:.35rem;overflow-wrap:anywhere}
.heard b{font-weight:500}
.heard[data-state="unsure"]{color:var(--warn)}
.heard[data-state="unsure"] b::before{content:"! "}
.heard a{color:var(--link);margin-left:.5rem}
/* Talk button: <button class="talk" data-state="ready|listening|thinking|speaking|error"><span class="talk-mark"></span>
   <span>Sprechen<small>Leertaste halten</small></span></button>; listening adds .progress-segs as the live level,
   thinking a .runner. Each state has its own mark shape: square, square, diamond, square, triangle. Height --h-l (D-3). */
.talk{position:relative;display:inline-flex;align-items:center;gap:.8rem;min-width:15rem;height:var(--h-l);padding:0 1.2rem;
  background:var(--bg1);border:0;color:var(--fg0);font-family:var(--font-heading);font-weight:700;font-size:var(--title-s);
  letter-spacing:var(--title-track);text-transform:uppercase;text-align:left;cursor:pointer;
  clip-path:polygon(0 0,calc(100% - var(--cut-m)) 0,100% var(--cut-m),100% 100%,var(--cut-m) 100%,0 calc(100% - var(--cut-m)))}
.talk:focus-visible{outline:2px solid var(--focus);outline-offset:-4px}
.talk small{display:block;font-family:var(--font-mono);font-weight:400;font-size:.6rem;letter-spacing:.12em;opacity:.8}
.talk .talk-mark{width:14px;height:14px;flex:none;background:var(--fg3)}
.talk[data-state="listening"]{background:var(--primary);color:var(--on-primary)}
.talk[data-state="listening"] .talk-mark{background:var(--on-primary)}
.talk[data-state="thinking"]{cursor:default}
.talk[data-state="thinking"] .talk-mark{background:var(--info);clip-path:polygon(50% 0,100% 50%,50% 100%,0 50%)}
.talk[data-state="speaking"] .talk-mark{background:var(--aqua)}
.talk[data-state="error"]{box-shadow:inset 0 -4px 0 var(--danger)}
.talk[data-state="error"] .talk-mark{background:var(--danger);clip-path:polygon(50% 0,100% 100%,0 100%)}
.talk .progress-segs{width:5rem}.talk .progress-segs>i{height:14px}
.talk[data-state="listening"] .progress-segs>i{background:var(--tint-2)}
.talk[data-state="listening"] .progress-segs>i.on{background:var(--on-primary)}
/* Diff: a correction as the title of a .hint-card. <span class="diff">コーヒー<del>を</del><ins>が</ins>好きです</span> */
.diff{line-height:1.9;color:var(--fg1)}
.diff del{text-decoration:line-through 2px var(--danger-text);color:var(--fg3)}
.diff ins{text-decoration:none;background:var(--cyan-tint);box-shadow:inset 0 -2px 0 var(--cyan);color:var(--fg0)}
/* Pitch curve: svg.pitch with .grid rules, .target (dashed step line), .actual (the learner, cyan, D-5),
   rect.kernel (accent) and rect.miss (danger); markers are square. */
.pitch{width:100%;max-width:26rem;height:auto;display:block}
.pitch .grid{stroke:var(--bg2);stroke-width:1}
.pitch .target{fill:none;stroke:var(--fg3);stroke-width:2;stroke-dasharray:6 4}
.pitch .actual{fill:none;stroke:var(--cyan);stroke-width:2}
.pitch .kernel{fill:var(--primary)}
.pitch .miss{fill:var(--danger)}
.pitch text{font-family:var(--font-mono);font-size:13px;fill:var(--fg2)}
/* Learning path (D-6): <div class="path"><a class="node" data-state="done|current|review|locked"><span class="mk"></span>
   <span><b>Title</b><small>N5-03 · 2 von 4</small></span></a>…</div>. Review nodes are indented as a side branch;
   a locked node says so in its small line. */
.path{display:flex;flex-direction:column;gap:.5rem;max-width:22rem}
.path .node{display:flex;align-items:center;gap:.8rem;padding:.55rem .8rem;background:var(--bg1);box-shadow:inset 4px 0 0 var(--bg2);color:inherit;text-decoration:none;
  clip-path:polygon(0 0,calc(100% - var(--cut-s)) 0,100% var(--cut-s),100% 100%,0 100%)}
.path .node:focus-visible{outline:2px solid var(--focus);outline-offset:-2px}
.path .node b{display:block;font-family:var(--font-heading);font-weight:700;font-size:var(--title-s);letter-spacing:var(--title-track);text-transform:uppercase;color:var(--fg0)}
.path .node small{display:block;font-family:var(--font-mono);font-size:.62rem;letter-spacing:.08em;color:var(--fg3)}
.path .node .mk{width:12px;height:12px;flex:none;background:var(--bg2)}
.path .node[data-state="done"]{box-shadow:inset 4px 0 0 var(--aqua)}
.path .node[data-state="done"] .mk{background:var(--aqua);clip-path:polygon(0 55%,20% 35%,40% 55%,85% 5%,100% 25%,40% 95%)}
.path .node[data-state="current"]{box-shadow:inset 4px 0 0 var(--primary);background:var(--tint-1)}
.path .node[data-state="current"] .mk{background:var(--primary)}
.path .node[data-state="review"]{box-shadow:inset 4px 0 0 var(--info);margin-left:1.6rem}
.path .node[data-state="review"] .mk{background:var(--info);clip-path:polygon(50% 0,100% 50%,50% 100%,0 50%)}
.path .node[data-state="open"] .mk{background:none;box-shadow:inset 0 0 0 2px var(--fg3)}
.path .node[data-state="locked"]{opacity:.55;pointer-events:none}
.path .node[data-state="locked"] .mk{visibility:hidden}
/* Goal meter (D-7): <span class="goalbar" role="progressbar" aria-valuenow="60"><i class="on"></i>…</span>, bottom to top. */
.goalbar{display:inline-flex;flex-direction:column-reverse;gap:2px;width:22px;vertical-align:middle}
.goalbar>i{height:4px;background:var(--bg2)}
.goalbar>i.on{background:var(--primary)}
