/* Toddoo browser runtime stylesheet · Toddoo BV.
 * The brand look comes from toddoo-components: the tokens (/assets/toddoo-tokens.css), the brand kit's components as
 * plain-markup classes with the AGENTS.md §23 names (/assets/toddoo-brand.css: .btn, .badge, .card, .glass*, .tabs/.tab,
 * .tbl, .inp/.field-error, .toggle/.check/.radio, .toast, .modal, .loop, .sidebar-item, .topbar, .scroll-glass, …),
 * the layout and text scale (/assets/toddoo-layout.css) and the icon CSS (/assets/toddoo-icon.css).
 * This file only maps our legacy markup onto that look where it differs from §23. It is not a design system.
 *
 * Two parts, so the kit always wins where its own classes are used:
 *  1. @layer toddoo-runtime-base: page base, type, the Materialize-compatible grid and helpers, and the look for bare
 *     elements (input, select, textarea, checkbox, radio, table). Unlayered CSS beats every layered rule, so a kit class
 *     (.inp, .check, .tbl, .btn …, all zero-specificity :where() rules) is never overridden by these.
 *  2. Unlayered: the legacy → canonical mappings for class names the kit does not have (.but, .switch .lever, .tab.active,
 *     .error_message, .input_field wrappers, the loaders, the side menu, the top bars, the Your Routes tiles), and the
 *     runtime's own UI (popups, toasts host, filters, dates, sign-in).
 * Light mode is the default (class "light" on <html> and <body>; dark: toddooRuntime.setTheme('dark')). No !important
 * wars: inline styles in widget markup still win and are listed as app-code changes in BUILD-NOTES-browser.md.
 * brand_lint.py (kit scripts/) runs clean on this file. */
@layer toddoo-runtime-base;

/* ================================================================ fonts (self-hosted, D-28; Montserrat only, AGENTS.md §1.1) */
@font-face { font-family: 'Montserrat'; font-style: normal; font-weight: 300; font-display: swap; src: url(/vendor/montserrat-5.2.8/montserrat-latin-300-normal.woff2) format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'Montserrat'; font-style: normal; font-weight: 400; font-display: swap; src: url(/vendor/montserrat-5.2.8/montserrat-latin-400-normal.woff2) format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'Montserrat'; font-style: normal; font-weight: 500; font-display: swap; src: url(/vendor/montserrat-5.2.8/montserrat-latin-500-normal.woff2) format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'Montserrat'; font-style: normal; font-weight: 600; font-display: swap; src: url(/vendor/montserrat-5.2.8/montserrat-latin-600-normal.woff2) format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'Montserrat'; font-style: normal; font-weight: 700 900; font-display: swap; src: url(/vendor/montserrat-5.2.8/montserrat-latin-700-normal.woff2) format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'Montserrat'; font-style: normal; font-weight: 300; font-display: swap; src: url(/vendor/montserrat-5.2.8/montserrat-latin-ext-300-normal.woff2) format('woff2'); unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family: 'Montserrat'; font-style: normal; font-weight: 400; font-display: swap; src: url(/vendor/montserrat-5.2.8/montserrat-latin-ext-400-normal.woff2) format('woff2'); unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family: 'Montserrat'; font-style: normal; font-weight: 500; font-display: swap; src: url(/vendor/montserrat-5.2.8/montserrat-latin-ext-500-normal.woff2) format('woff2'); unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family: 'Montserrat'; font-style: normal; font-weight: 600; font-display: swap; src: url(/vendor/montserrat-5.2.8/montserrat-latin-ext-600-normal.woff2) format('woff2'); unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family: 'Montserrat'; font-style: normal; font-weight: 700 900; font-display: swap; src: url(/vendor/montserrat-5.2.8/montserrat-latin-ext-700-normal.woff2) format('woff2'); unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }

/* ================================================================ runtime-only token aliases (built from kit tokens; the kit lacks these names) */
:root, body {
  --on-accent: #FFFFFF;                                   /* text and icon on a teal or red fill (AGENTS.md §10.1) */
  --focus-color: #00C8C8;                                 /* AGENTS.md §1.11: the focus ring is always #00C8C8 */
  --dialog-radius: var(--modal-radius);
  --btn-h: var(--btn-h-md);
}

/* ================================================================ legacy palette (D-27) on the brand tokens.
   Our markup's --color_* names, defined from the kit tokens (Toddoo's own default palette, global_functions.php:1582, maps
   onto them one to one). paint_framework() may change only the organiser's --color_accent and --color_flow. */
:root {
  --color_1: var(--text1); --color_2: var(--text1); --color_3: var(--text1);
  --color_4: var(--grey); --color_5: var(--grey); --color_6: var(--grey);
  --color_7: var(--border); --color_8: var(--border);
  --color_bg: var(--bg); --color_fg: var(--surface);
  --color_flow: var(--teal); --color_accent: var(--teal); --color_accent_fb: var(--success);
  --color_alert: var(--red); --color_cancel: var(--text2);
  --color_text_dark: var(--text1); --color_text_light: var(--on-accent); --text_dark: var(--text1);
}
/* B-24 dark mode. Our markup uses --color_text_light both as a card background (419 inline "background-color:
   var(--color_text_light)") and as text on teal fills (white on #1A7587 in light). In dark the fills are the readable
   #00C8C8, which takes dark text (AGENTS.md §4.1, §10.1), and cards are dark surfaces; so in dark it is the surface colour,
   right for both uses. Light is unchanged (white). */
:root:not(.light) { --color_text_light: var(--surface); }
/* Popup dim (design "Add cart line", option A chosen, 6 Oct 2026): in light mode every popup sits on a 24% ink dim instead of
   50% black; the popup keeps its glass fill. Read by the kit's .modal-backdrop, <toddoo-dialog> and native <dialog> popups.
   Declared on body too: kit tokens re-declared on body.light win over :root (brand kit v3.2 note). Dark mode keeps the kit's dim. */
:root.light, :root.light body, body.light { --modal-backdrop: rgba(15, 26, 29, .24); }

/* ================================================================================================================ */
/* 1. BASE LAYER: page, type, grid and helpers, bare elements. The kit's classes always win over this layer.         */
/* ================================================================================================================ */
@layer toddoo-runtime-base {
  html, body { font-family: 'Montserrat', -apple-system, 'Segoe UI', Arial, sans-serif; }
  body {
    margin: 0; background-color: var(--bg); color: var(--text1); font-size: 14px;
    /* no body line-height: our pixel-laid-out screens (the template builder's absolute boxes, vh tiles) were measured at the
       browser default, and the library sets none either */
    -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility;
  }
  /* neutral luminosity backdrop (§7.4): white/dark pools only, never a brand colour */
  :root.light body { background-image: radial-gradient(ellipse at 15% 25%, rgba(0,0,0,.04) 0%, transparent 45%), radial-gradient(ellipse at 80% 15%, rgba(0,0,0,.03) 0%, transparent 40%), radial-gradient(ellipse at 65% 85%, rgba(0,0,0,.025) 0%, transparent 45%); background-attachment: fixed; }
  :root:not(.light) body { background-image: radial-gradient(ellipse at 15% 25%, rgba(255,255,255,.08) 0%, transparent 45%), radial-gradient(ellipse at 80% 15%, rgba(255,255,255,.06) 0%, transparent 40%), radial-gradient(ellipse at 65% 85%, rgba(255,255,255,.05) 0%, transparent 45%); background-attachment: fixed; }
  *, *::before, *::after { box-sizing: border-box; }
  a { color: var(--teal); text-decoration: none; }
  a:hover { color: var(--teal-dk); }
  button, input, select, textarea { font: inherit; color: inherit; }
  img { max-width: 100%; }
  :focus-visible { outline: none; box-shadow: var(--focus-ring); }
  h1, h2, h3, h4, h5, h6 { margin: 0 0 var(--sp-3); color: var(--text1); }
  h1 { font-size: var(--t-text-2xl); font-weight: 700; line-height: 1.2; }
  h2 { font-size: var(--t-text-xl); font-weight: 700; line-height: 1.25; }
  h3 { font-size: var(--t-text-l); font-weight: 700; line-height: 1.3; }
  h4, h5, h6 { font-size: var(--t-text-m); font-weight: 700; line-height: 1.35; }
  p { margin: 0 0 var(--sp-3); }
  /* our .h1-.h6 are size utilities on spans and divs, not headings: the library's text scale by role (B-18) */
  .h1 { font-size: var(--t-text-2xl); font-weight: 700; line-height: 1.2; }
  .h2 { font-size: var(--t-text-xl); font-weight: 700; line-height: 1.25; }
  .h3 { font-size: var(--t-text-l); font-weight: 600; line-height: 1.3; }
  .h4 { font-size: var(--t-text-m); line-height: 1.4; }
  .h5 { font-size: var(--t-text-s); line-height: 1.45; }
  .h6 { font-size: var(--t-text-xs); line-height: 1.45; }

  /* Materialize-compatible grid and helpers (D-20, written fresh) */
  .container { margin: 0 auto; max-width: var(--max-content); width: 90%; }
  .row { --row-gap: 0px; margin-left: auto; margin-right: auto; margin-bottom: var(--sp-5); }
  .row::after { content: ""; display: table; clear: both; }
  .row > .row { width: 100%; }
  .col { --c: initial; float: left; box-sizing: border-box; padding: 0 calc(var(--gap-size, var(--sp-6)) / 2); min-height: 1px; }
  /* a column of N twelfths: N/12 of the row minus its share of the row's gap, so N columns plus the gaps between them fill
     the row exactly. --row-gap is 0 on every row (identical to the plain percentages) except a row the app gives a gap
     (inline or in a widget style): the runtime marks it .tdr-gap-row, copies the gap into --row-gap and lays it out as a
     wrapping flex row (87-responsive.js), as the app expects. An offset of N twelfths is N columns plus N gaps. */
  .col:is(.s1,.s2,.s3,.s4,.s5,.s6,.s7,.s8,.s9,.s10,.s11,.s12,.m1,.m2,.m3,.m4,.m5,.m6,.m7,.m8,.m9,.m10,.m11,.m12,.l1,.l2,.l3,.l4,.l5,.l6,.l7,.l8,.l9,.l10,.l11,.l12,.xl1,.xl2,.xl3,.xl4,.xl5,.xl6,.xl7,.xl8,.xl9,.xl10,.xl11,.xl12) { width: calc(var(--c) * 100% / 12 - var(--row-gap) * (12 - var(--c)) / 12); }
  .col.s1{--c:1}.col.s2{--c:2}.col.s3{--c:3}.col.s4{--c:4}.col.s5{--c:5}.col.s6{--c:6}.col.s7{--c:7}.col.s8{--c:8}.col.s9{--c:9}.col.s10{--c:10}.col.s11{--c:11}.col.s12{--c:12}
  .col.offset-s1{margin-left:calc(1 * (100% + var(--row-gap)) / 12)}.col.offset-s2{margin-left:calc(2 * (100% + var(--row-gap)) / 12)}.col.offset-s3{margin-left:calc(3 * (100% + var(--row-gap)) / 12)}.col.offset-s4{margin-left:calc(4 * (100% + var(--row-gap)) / 12)}.col.offset-s6{margin-left:calc(6 * (100% + var(--row-gap)) / 12)}
  @media (min-width: 601px) {
    .col.m1{--c:1}.col.m2{--c:2}.col.m3{--c:3}.col.m4{--c:4}.col.m5{--c:5}.col.m6{--c:6}.col.m7{--c:7}.col.m8{--c:8}.col.m9{--c:9}.col.m10{--c:10}.col.m11{--c:11}.col.m12{--c:12}
    .col.offset-m1{margin-left:calc(1 * (100% + var(--row-gap)) / 12)}.col.offset-m2{margin-left:calc(2 * (100% + var(--row-gap)) / 12)}.col.offset-m3{margin-left:calc(3 * (100% + var(--row-gap)) / 12)}.col.offset-m4{margin-left:calc(4 * (100% + var(--row-gap)) / 12)}.col.offset-m6{margin-left:calc(6 * (100% + var(--row-gap)) / 12)}
  }
  @media (min-width: 993px) {
    .col.l1{--c:1}.col.l2{--c:2}.col.l3{--c:3}.col.l4{--c:4}.col.l5{--c:5}.col.l6{--c:6}.col.l7{--c:7}.col.l8{--c:8}.col.l9{--c:9}.col.l10{--c:10}.col.l11{--c:11}.col.l12{--c:12}
    .col.offset-l1{margin-left:calc(1 * (100% + var(--row-gap)) / 12)}.col.offset-l2{margin-left:calc(2 * (100% + var(--row-gap)) / 12)}.col.offset-l3{margin-left:calc(3 * (100% + var(--row-gap)) / 12)}.col.offset-l4{margin-left:calc(4 * (100% + var(--row-gap)) / 12)}.col.offset-l6{margin-left:calc(6 * (100% + var(--row-gap)) / 12)}
  }
  @media (min-width: 1201px) {
    .col.xl1{--c:1}.col.xl2{--c:2}.col.xl3{--c:3}.col.xl4{--c:4}.col.xl5{--c:5}.col.xl6{--c:6}.col.xl7{--c:7}.col.xl8{--c:8}.col.xl9{--c:9}.col.xl10{--c:10}.col.xl11{--c:11}.col.xl12{--c:12}
  }
  .row.tdr-gap-row { display: flex; flex-wrap: wrap; }
  .row.tdr-gap-row::after { display: none; }
  .row.tdr-gap-row > .col { float: none; flex: none; }
  /* a row of card columns without a gap of its own: the kit's gap between cards (§8) */
  .row.tdr-card-row { --row-gap: var(--sp-3); gap: var(--sp-3); }
  .valign-wrapper { display: flex; align-items: center; }
  .center, .center-align { text-align: center; }
  .left-align { text-align: left; }
  .right-align { text-align: right; }
  .left { float: left !important; } .right { float: right !important; }
  .hide { display: none !important; }
  .show { display: block; }
  @media (max-width: 600px) { .hide-on-small-only, .hide-on-small-and-down { display: none !important; } }
  @media (max-width: 992px) { .hide-on-med-and-down { display: none !important; } }
  @media (min-width: 601px) { .hide-on-med-and-up { display: none !important; } }
  @media (min-width: 993px) { .hide-on-large-only { display: none !important; } }
  /* elevation: no heavy shadows (AGENTS.md §7.7); Materialize z-depth becomes a hairline, hover the accent edge */
  .z-depth-0 { box-shadow: none; }
  .z-depth-1, .z-depth-2, .z-depth-3, .z-depth-4, .z-depth-5 { box-shadow: 0 0 0 1px var(--border); }
  .hoverable { cursor: pointer; transition: box-shadow var(--dur-small); }
  .hoverable:hover { box-shadow: 0 0 0 1px var(--accent); }
  .responsive-img { max-width: 100%; height: auto; }
  .circle { border-radius: 50%; }
  .divider { height: 1px; overflow: hidden; background-color: var(--border); }
  /* a legacy .badge without a kit variant: the neutral badge (before the colour helpers, so "badge green" still wins) */
  :where(.badge:not(.badge-s, .badge-w, .badge-e, .badge-i, .badge-n)) { background: var(--badge-neutral-bg); color: var(--badge-neutral-text); }
  /* colour helpers on brand tokens: Materialize names keep working, the colours are Toddoo's */
  .white-text { color: var(--on-accent); } .black-text, .text-black { color: var(--text1); } .grey-text { color: var(--text2); }
  .green-text { color: var(--teal-dk); } .red-text { color: var(--red); } .blue-text, .teal-text { color: var(--teal); }
  .red { background-color: var(--red); color: var(--on-accent); } .green { background-color: var(--success); color: var(--badge-success-text); }
  .blue, .teal { background-color: var(--teal); color: var(--on-accent); } .orange { background-color: var(--yellow); color: var(--badge-warning-text); }
  .white { background-color: var(--surface); } .grey { background-color: var(--grey); color: var(--on-accent); }

  /* framework class names our widgets share (§7.4 b) */
  .valign_wrapper { display: flex; align-items: center; }
  .valign_wrapper_gap_1 { display: flex; align-items: center; gap: var(--sp-2); }
  .valign_wrapper_between { display: flex; align-items: center; justify-content: space-between; }
  .valign_wrapper_center { display: flex; align-items: center; justify-content: center; }
  .valign_wrapper_right { display: flex; align-items: center; justify-content: flex-end; }
  .valign-column { display: flex; flex-direction: column; }
  .flex-container, .flex_container { display: flex; }
  .flex_container_column { display: flex; flex-direction: column; }
  .flex_container_end { display: flex; justify-content: flex-end; align-items: center; }
  .flex_container_between { display: flex; justify-content: space-between; align-items: center; }
  .page_container { padding: var(--sp-6); height: 100%; overflow-y: auto; }
  .table_scrollable { overflow-x: auto; max-width: 100%; }
  .scroll_container { overflow: auto; }
  .mb-1{margin-bottom:var(--sp-1)}.mb-2{margin-bottom:var(--sp-2)}.mb-3{margin-bottom:var(--sp-4)}.mb-4{margin-bottom:var(--sp-6)}.mb-5{margin-bottom:var(--sp-12)}
  .mt-1{margin-top:var(--sp-1)}.mt-2{margin-top:var(--sp-2)}.mt-3{margin-top:var(--sp-4)}.mt-4{margin-top:var(--sp-6)}.mt-5{margin-top:var(--sp-12)}
  .ml-1{margin-left:var(--sp-1)}.ml-2{margin-left:var(--sp-2)}.ml-3{margin-left:var(--sp-4)}.mr-1{margin-right:var(--sp-1)}.mr-2{margin-right:var(--sp-2)}.mr-3{margin-right:var(--sp-4)}
  .my-5{margin-top:var(--sp-12);margin-bottom:var(--sp-12)}.py-5{padding-top:var(--sp-12);padding-bottom:var(--sp-12)}.px-3{padding-left:var(--sp-4);padding-right:var(--sp-4)}
  .cancel { color: var(--text2); }
  .accent { color: var(--teal); }
  .color_1{color:var(--color_1)}.color_2{color:var(--color_2)}.color_3{color:var(--color_3)}.color_4{color:var(--color_4)}
  .color_5{color:var(--color_5)}.color_6{color:var(--color_6)}.color_7{color:var(--color_7)}.color_8{color:var(--color_8)}
  .color_text_dark{color:var(--color_text_dark)}.color_text_light{color:var(--color_text_light)}.color_cancel{color:var(--color_cancel)}.color_alert{color:var(--color_alert)}
  .truncate, .truncatex { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .truncatex { display: block; max-width: 100%; }
  .hoverable_text, .text_hover { cursor: pointer; transition: color var(--dur-small); }
  .hoverable_text:hover, .text_hover:hover { color: var(--teal); }
  .clickable { cursor: pointer; }
  @media print { .no-print { display: none !important; } }
  .currency_symbol { color: var(--text2); font-weight: 500; }
  .upload_trigger { cursor: pointer; }
  .custom_checkbox, .checkbox_container { display: inline-flex; align-items: center; gap: var(--sp-2); cursor: pointer; }
  .checkbox_label { cursor: pointer; }
  .filled { background-color: var(--accent-dim); }
  .fixed-action-btn { position: fixed; right: var(--sp-6); bottom: var(--sp-6); z-index: var(--z-sticky); }
  .fixed-action-btn ul { list-style: none; margin: 0 0 var(--sp-3); padding: 0; display: none; text-align: center; }
  .fixed-action-btn.active ul { display: block; }
  .waves-effect, .waves-light { position: relative; overflow: hidden; }

  /* bare fields: the kit's .inp look (§10.2) for inputs our markup writes without .inp */
  :is(input:not([type]), input[type=text], input[type=email], input[type=password], input[type=search], input[type=tel], input[type=url],
  input[type=number], input[type=date], input[type=datetime-local], input[type=time], select):not(toddoo-search > input, toddoo-stepper > input) {
    min-height: var(--input-h); padding: 0 var(--input-px); border: var(--input-border); border-radius: var(--input-radius);
    background-color: var(--surface2); color: var(--text1); font-size: 13px; outline: none;
    transition: border-color var(--dur-small) var(--ease-out), box-shadow var(--dur-small) var(--ease-out);
  }
  /* date / time fields: iOS Safari gives the native control an intrinsic width wider than its box and centres its value, so
     on a phone it ran out of the card while the text fields next to it fitted (Hanko, 11 Oct 2026, EA shop details).
     Same box and alignment as every other field; a screen that wants a narrower date field sets its own width (.eo-bar). */
  :is(input[type=date], input[type=datetime-local], input[type=time], input[type=month]) {
    -webkit-appearance: none; appearance: none; display: block; width: 100%; max-width: 100%; min-width: 0; box-sizing: border-box; text-align: left;
  }
  :is(input[type=date], input[type=datetime-local], input[type=time], input[type=month])::-webkit-date-and-time-value { text-align: left; }
  textarea { min-height: 80px; padding: var(--sp-3) var(--sp-4); border: var(--input-border); border-radius: var(--textarea-radius); background-color: var(--surface2); color: var(--text1); font-size: 13px; resize: vertical; outline: none; }
  :is(input, select, textarea):focus:not(toddoo-search > input, toddoo-stepper > input) { border: var(--input-focus); }
  :is(input, select, textarea):focus-visible:not(toddoo-search > input, toddoo-stepper > input) { box-shadow: var(--focus-ring); }
  input:disabled, select:disabled, textarea:disabled { opacity: var(--btn-disabled-opacity); cursor: not-allowed; }
  input[aria-invalid="true"], select[aria-invalid="true"], textarea[aria-invalid="true"] { border: var(--input-error); }
  ::placeholder { color: var(--text3); opacity: 1; }
  label { color: var(--text2); font-size: 12px; font-weight: 500; }
  /* bare checkboxes and radios: the kit's .check / .radio look (§10.3, §23): 18px, radius 4 / round, teal when on */
  input[type=checkbox], input[type=radio] {
    appearance: none; -webkit-appearance: none; flex: 0 0 auto; display: inline-grid; place-items: center; width: 18px; height: 18px;
    min-height: 0; margin: 0; padding: 0; border: 1.5px solid var(--border); background: var(--surface2); vertical-align: middle; cursor: pointer;
  }
  input[type=checkbox] { border-radius: var(--radius-xs); }
  input[type=checkbox]:checked { border-color: var(--teal); background: var(--teal); }
  input[type=checkbox]:checked::after { content: ""; width: 5px; height: 9px; margin-top: -2px; border-right: 2px solid var(--bg); border-bottom: 2px solid var(--bg); transform: rotate(45deg); }
  input[type=radio] { border-radius: 50%; }
  input[type=radio]:checked { border-color: var(--teal); }
  input[type=radio]:checked::after { content: ""; width: 10px; height: 10px; border-radius: 50%; background: var(--teal); }
  input[type=checkbox]:disabled, input[type=radio]:disabled { opacity: var(--btn-disabled-opacity); cursor: not-allowed; }
  /* bare tables: the kit's .tbl look (§10.9): 9px header, row dividers, pill row hover, no zebra */
  table { width: 100%; border-collapse: separate; border-spacing: 0 var(--tbl-row-gap); font-size: var(--tbl-body-font); color: var(--text2); }
  th { padding: var(--tbl-cell-py) var(--tbl-cell-px); border-bottom: 1px solid var(--border); text-align: left; font-size: var(--tbl-header-font); font-weight: 700; letter-spacing: 1px; text-transform: uppercase; color: var(--text3); }
  td { padding: var(--tbl-cell-py) var(--tbl-cell-px); box-shadow: 0 1px 0 0 var(--border); }
  td.primary { color: var(--text1); font-weight: 600; }
  tbody tr:hover > td { background: var(--accent-dim); box-shadow: none; }
  tbody tr:hover > td:first-child { border-radius: var(--tbl-row-radius) 0 0 var(--tbl-row-radius); }
  tbody tr:hover > td:last-child { border-radius: 0 var(--tbl-row-radius) var(--tbl-row-radius) 0; }

  /* until the runtime replaces it with a brand icon (B-19), the Material ligature word is not shown (no icon font) */
  .material-icons, .material-icons-outlined, .material-icons-round, .material-symbols-outlined, .material-symbols-rounded { display: inline-block; width: 1em; height: 1em; overflow: hidden; font-size: 24px; line-height: 1; color: transparent; vertical-align: middle; }
}

/* ================================================================================================================ */
/* 2. LEGACY → CANONICAL MAPPINGS (unlayered; class names the kit does not have, or legacy variants of kit names)     */
/* ================================================================================================================ */

/* ---------------------------------------------------------------- buttons (§10.1): legacy .but onto the kit's .btn look.
   .but.flow / .primary / .accent → .btn-p (the organiser's --color_flow, teal by default); .but.cancel → .btn-s;
   .but.outline → .btn-op; .but.alert / .danger → .btn.danger; a bare .but → .btn-os. Fill ↔ outline swap on hover and pressed. */
:where(.but) {
  --_btn-c: var(--grey); --_btn-on: var(--bg);
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  min-height: var(--btn-h-md); padding: 0 var(--btn-px-md); border: var(--btn-border) solid var(--_btn-c); border-radius: var(--btn-radius);
  background: transparent; color: var(--_btn-c); font: inherit; font-size: 12px; font-weight: 600; line-height: 1;
  white-space: nowrap; text-decoration: none; text-transform: none; cursor: pointer; user-select: none;
  transition: background var(--dur-small) var(--ease-out), color var(--dur-small) var(--ease-out), border-color var(--dur-small) var(--ease-out), transform var(--dur-micro) linear;
}
:where(.but.flow, .but.primary, .but.accent, .but.outline) { --_btn-c: var(--color_flow); }
:where(.but.alert, .but.danger) { --_btn-c: var(--red); --_btn-on: var(--on-accent); }
:where(.but.flow, .but.primary, .but.accent, .but.cancel, .but.alert, .but.danger) { background: var(--_btn-c); color: var(--_btn-on); }
:where(.but.flow, .but.primary, .but.accent, .but.cancel, .but.alert, .but.danger):where(:hover, :active) { background: transparent; color: var(--_btn-c); }
:where(.but:not(.flow, .primary, .accent, .cancel, .alert, .danger)):where(:hover, :active) { background: var(--_btn-c); color: var(--_btn-on); }
:where(.but:active) { transform: scale(var(--interact-scale)); }
:where(.but:focus-visible) { outline: none; box-shadow: var(--btn-focus); }
:where(.but:disabled, .but.disabled, .but[disabled]) { opacity: var(--btn-disabled-opacity); cursor: not-allowed; transform: none; pointer-events: none; }
/* Materialize .btn variants in our markup (105 bare "btn", "btn cancel", "btn alert", "btn-red" …) on the kit's .btn */
:where(.btn.cancel) { --_btn-c: var(--grey); }
:where(.btn.alert, .btn.red, .btn-red) { --_btn-c: var(--red); --_btn-on: var(--on-accent); }
/* a Materialize .btn is the filled button: the kit's fill → outline swap applies to it as to .btn-p */
:where(.btn:not(.btn-p, .btn-s, .btn-op, .btn-os, .btn-bl, .danger)):where(:hover, :active) { background: transparent; color: var(--_btn-c); }
/* sizes: Materialize .btn-small (148 uses, nearly all "btn-small but") → the kit's small button */
:where(.but.btn-small, .btn-small) { min-height: var(--btn-h-sm); padding: 0 var(--btn-px-sm); font-size: 11px; }
:where(.btn.btn-small) { height: var(--btn-h-sm); }
/* Materialize .btn-floating → the kit's icon-only circle (.btn-ico) */
:where(.btn-floating) { display: inline-grid; place-items: center; width: var(--btn-icon-md); height: var(--btn-icon-md); padding: 0; border: 0; border-radius: var(--btn-icon-radius); background: var(--teal); color: var(--bg); cursor: pointer; }

/* ---------------------------------------------------------------- fields (§10.2, §10.18) */
/* composite fields: .input_field on a wrapper (42 uses) and the legacy .input_container (78: currency or icon + input). The
   wrapper is the kit's pill field, the input inside it is bare, and the icon or prefix sits beside it on one line (form audit
   F-02). The legacy .search_container (130: magnifier + input + loader) is no longer styled here: toddoo.search.upgrade turns
   it into the library's <toddoo-search> (R-18), which draws the pill, the icon, the × and the Loop itself. */
:where(div.input_field, span.input_field, label.input_field, .input_container):where(:not(.toddoo-search-host, :has(> toddoo-stepper))) {
  display: inline-flex; align-items: center; gap: var(--sp-2); min-height: var(--input-h); padding: 0 var(--input-px);
  border: var(--input-border); border-radius: var(--input-radius); background-color: var(--surface2); color: var(--text1); font-size: 13px;
}
:where(div.input_field, span.input_field, label.input_field, .input_container):where(:not(.toddoo-search-host, :has(> toddoo-stepper))) :where(input:not(toddoo-search > input, toddoo-stepper > input), select) { flex: 1 1 auto; align-self: stretch; min-width: 0; min-height: 0; padding: 0; border: 0; border-radius: 0; background: transparent; box-shadow: none; }
:where(div.input_field, span.input_field, label.input_field, .input_container):where(:not(.toddoo-search-host, :has(> toddoo-stepper))):focus-within { border: var(--input-focus); box-shadow: var(--focus-ring); }
:where(div.input_field, span.input_field, label.input_field, .input_container):where(:not(.toddoo-search-host, :has(> toddoo-stepper))) > :where(svg, .svg_icon, span, .swf_loop_host) { flex: 0 0 auto; }
:where(div.input_field, span.input_field, label.input_field, .input_container):where(:not(.toddoo-search-host, :has(> toddoo-stepper))) { max-width: 100%; }
:where(.input_loader:not(toddoo-search > input, toddoo-stepper > input)) { padding-right: var(--sp-8); }
/* legacy errors → the kit's .field-error (§10.18): the alert icon in red, a 1.5px red border on the field, neutral words */
:where(.invalid_input, .input_field.invalid) { border: var(--input-error); }
:where(.error_message:not(:empty)) { display: flex; align-items: flex-start; gap: 6px; margin-top: 2px; font-size: 11px; font-weight: 500; line-height: 1.4; color: var(--text1); }
:where(.error_message:not(:empty))::before {
  content: ""; flex: 0 0 auto; width: 14px; height: 14px; margin-top: 1px; background: var(--red);
  -webkit-mask: url(/assets/icons/alert.svg) center / contain no-repeat; mask: url(/assets/icons/alert.svg) center / contain no-repeat;
}
/* R-27 with legacy errors: the kit's .help hides while a .field-error shows; our markup shows errors as .error_message
   siblings (inserted after the field, hidden again with jQuery .hide(), which writes display: none inline) and marks the field
   .invalid / .invalid_input / aria-invalid. So a .help gives way while a visible, non-empty .error_message is its sibling
   (before or after it), or while a sibling field is marked invalid. Zero specificity, like the kit.
   7 Oct 2026 (floorplan speed): no [style*=...] inside :has() any more, and the two forms `:has(> X) > .help` are gone (they
   said the same as the sibling forms: a child of .help's parent is a sibling of .help). A style attribute inside a :has()
   argument makes Chrome re-check the whole page after EVERY inline style write anywhere (jQuery .css/.show, Leaflet):
   15-18 ms per write on the 330-booth floorplan, ~6 s per GET_RCB poll; 0.04 ms without it. So an error after the .help
   that is hidden with .hide() (not removed) keeps the .help hidden; the app removes its errors (`.error_message').remove()`).
   Never put [style...] in a :has() argument. */
:where(
  .error_message:not(:empty, [hidden], [style*="display: none"], [style*="display:none"]) ~ .help,
  .help:has(~ .error_message:not(:empty, [hidden])),
  :is(.invalid, .invalid_input, [aria-invalid="true"]) ~ .help,
  .help:has(~ :is(.invalid, .invalid_input, [aria-invalid="true"]))
) { display: none; }
/* legacy .switch > label > input + .lever (107 uses) → the kit's .toggle: track 42×24, knob 18, on = teal */
:where(.switch label) { display: inline-flex; align-items: center; gap: var(--sp-2); font-size: 13px; color: var(--text1); cursor: pointer; }
:where(.switch label input[type=checkbox]) { position: absolute; opacity: 0; width: 1px; height: 1px; margin: 0; pointer-events: none; }
:where(.switch label .lever) { position: relative; flex: 0 0 auto; display: inline-block; width: 42px; height: 24px; border-radius: 12px; background: var(--border); transition: background .2s ease; vertical-align: middle; }
:where(.switch label .lever)::after { content: ""; position: absolute; top: 3px; left: 3px; width: 18px; height: 18px; border-radius: 50%; background: var(--on-accent); box-shadow: 0 1px 2px rgba(0,0,0,.2); transition: transform .2s ease; }
:where(.switch label input[type=checkbox]:checked + .lever) { background: var(--teal); }
:where(.switch label input[type=checkbox]:checked + .lever)::after { transform: translateX(18px); }
:where(.switch label input[type=checkbox]:focus-visible + .lever) { box-shadow: var(--focus-ring); }
:where(.switch label input[type=checkbox]:disabled + .lever) { opacity: var(--btn-disabled-opacity); cursor: not-allowed; }

/* ---------------------------------------------------------------- tabs (§10.13): legacy selected state → the kit's .tab.on */
:where(.tab.active, .tab.selected) { border-color: var(--interact-select-border); background: var(--interact-select-bg); color: var(--accent); }
/* Materialize structure ul.tabs > li.tab > a(.active): the link is the pill, the list item carries nothing */
:where(ul.tabs) { list-style: none; margin: 0 0 var(--sp-4); padding-left: 0; }
:where(ul.tabs > li.tab) { padding: 0; border: 0; background: transparent; }
:where(ul.tabs > li.tab > a) { display: inline-flex; align-items: center; padding: var(--tab-py) var(--tab-px); border: var(--tab-border) solid transparent; border-radius: var(--tab-radius); color: var(--text3); font-size: var(--tab-font); font-weight: 600; }
:where(ul.tabs > li.tab > a:hover) { background: var(--interact-hover-bg); color: var(--teal); }
:where(ul.tabs > li.tab > a.active) { border-color: var(--interact-select-border); background: var(--interact-select-bg); color: var(--accent); }

/* ---------------------------------------------------------------- chips (9 uses): the kit's neutral badge, a little taller */
:where(.chip, .pill) { display: inline-flex; align-items: center; gap: var(--sp-1); min-height: 28px; padding: 0 var(--sp-3); margin: 0 var(--sp-1) var(--sp-1) 0; border-radius: var(--badge-radius); background: var(--badge-neutral-bg); color: var(--badge-neutral-text); font-size: 11px; font-weight: 600; }

/* ---------------------------------------------------------------- cards (§10.8): a legacy .card without a glass class gets the
   L2 glass surface (fill, edge, highlight, blur; the kit's .glass adds reflection and noise through its own pseudo-elements,
   which legacy cards may already use) */
:where(.card:not(.glass-subtle, .glass, .glass-elevated, .glass-solid)) {
  position: relative; margin: var(--sp-2) 0 var(--sp-4); background: var(--glass-2);
  -webkit-backdrop-filter: blur(var(--glass-blur-2, 24px)); backdrop-filter: blur(var(--glass-blur-2, 24px));
  box-shadow: inset 0 0 0 1px var(--glass-b2), inset 1px 1px 0 0 var(--glass-hi2), 0 0 0 1px var(--border);
}
:where(.card .card-content) { padding: 0; }
/* "Your Routes" tiles (start_www): the widget's <style> sets them in vh; this is one class above. Card radius and surface. */
.toddoo-runtime .routes_items { border: 1px solid var(--border); border-radius: var(--card-radius, var(--radius-2xl)); overflow: hidden; background: var(--surface); color: var(--text1); font-size: var(--t-text-s); transition: border-color var(--dur-small), transform var(--dur-small); }
.toddoo-runtime .routes_items:hover { border-color: var(--accent); }
.toddoo-runtime .routes_items > .row:first-child { margin-bottom: 0; background-color: var(--surface2); }
.toddoo-runtime .routes_items .truncate_1 { color: var(--text2); }

/* ---------------------------------------------------------------- app chrome: the top bars → the kit's .topbar look (§8.3) and the
   icon rail → .sidebar / .sidebar-item (§10.13). Heights and positions stay the widget's. */
.toddoo-runtime #header_cube, .toddoo-runtime #top_bar_cube { background: var(--hdr-bg); box-shadow: inset 0 -1px 0 0 var(--hdr-border); color: var(--text1); }
.toddoo-runtime .organiser_menu {
  padding: var(--sp-2) 0; row-gap: var(--sp-1); border-radius: var(--radius-2xl); background: var(--glass-1);
  -webkit-backdrop-filter: blur(var(--glass-blur-1, 16px)); backdrop-filter: blur(var(--glass-blur-1, 16px));
  box-shadow: inset 0 0 0 1px var(--glass-b1), inset 1px 1px 0 0 var(--glass-hi1), 0 0 0 1px var(--border);
}
/* the rail items: .tdo-menu with the stored menu name in data-menu (.menu_container / menu_container="…" until 10 Oct 2026) */
.toddoo-runtime .tdo-menu { border: 2px solid transparent; border-radius: 50%; color: var(--text2); transition: background var(--dur-small), color var(--dur-small), transform var(--dur-micro); }
.toddoo-runtime .tdo-menu:hover { background-color: var(--accent-dim); color: var(--text1); }
.toddoo-runtime .tdo-menu:active { transform: scale(.95); }
.toddoo-runtime .tdo-menu.active { background-color: var(--teal); border-color: var(--accent); color: var(--bg); }
/* legacy chrome sized in vh (top bar 6–7vh, rail items 3.5vh, rail icons 2.3vh !important) grew to 130px / 76px on a 4K
   screen and shrank below the kit sizes on short ones. min-/max- bounds limit width and height even when those are inline
   or !important, so no override war is needed: top bar 52–64px (§8.3), rail items 36–44px and icons 20–24px (§10.13). */
.toddoo-runtime #header_cube, .toddoo-runtime #top_bar_cube { min-height: var(--header-h); max-height: 64px; }
.toddoo-runtime .tdo-menu { min-width: var(--sb-icon-size); min-height: var(--sb-icon-size); max-width: 44px; max-height: 44px; }
.toddoo-runtime .tdo-menu svg { min-width: 20px; min-height: 20px; max-width: 24px; max-height: 24px; }
/* the top-bar counters (widget style: font-size 0.8vh; width 1.5vh): readable at every height (10–12px, 16px minimum circle) */
.toddoo-runtime .counter_circle { font-size: clamp(10px, 0.8vh, 12px); min-width: 16px; min-height: 16px; line-height: 16px; }
/* the rail item's name bubble (.menu_text.z-depth-1 until 10 Oct 2026: the hairline the z-depth rule gave it is kept here) */
.toddoo-runtime .tdo-menu-text { border: 1px solid var(--border); border-radius: var(--tip-radius); padding: var(--tip-py) var(--tip-px); background: var(--surface); color: var(--text1); font-size: var(--t-text-xs); font-weight: 500; box-shadow: 0 0 0 1px var(--border); }
.toddoo-runtime #organiser_menu .tdo-menu-text { box-shadow: none; }   /* the EA console's bubbles never had the z-depth ring */

/* ---------------------------------------------------------------- loaders → the kit's .loop (§3, §10.17; the CSS is the kit's) */
/* our loader markup: <span class="swf_loop_host loading_circle"><span class="loop"></span></span>, sized by the host */
.swf_loop_host { display: inline-flex; align-items: center; justify-content: center; width: var(--spinner-xs); height: var(--spinner-xs); vertical-align: middle; }
.swf_loop_host.h2, .swf_loop_host.title_loading_circle { width: var(--spinner-sm); height: var(--spinner-sm); }
.swf_loop_host .loop { width: 100%; height: 100%; }
.input_loader ~ .swf_loop_host.loading_circle { visibility: hidden; }
.input_loader.loading ~ .swf_loop_host.loading_circle { visibility: visible; }
/* the #loading overlay of the start widgets: the old spinner image hidden; the runtime puts a .loop.loop-64 inside */
.spinning_loader { position: fixed !important; left: 50%; top: 50%; transform: translate(-50%, -50%); z-index: var(--z-modal); display: none; pointer-events: none; }
.spinning_loader.tdr-loading-on { display: block; }
/* the page loader (#loading, any console): centred in the viewport, above the header bands, 80px Loop (6 Oct 2026) */
#loading.tdr-loader { position: fixed !important; inset: 0 !important; left: 0 !important; top: 0 !important; transform: none !important;
  width: auto !important; height: auto !important; max-height: none !important; margin: 0 !important; padding: 0 !important;
  display: none; align-items: center; justify-content: center; z-index: 2147483000 !important; pointer-events: none; background: transparent; }
#loading.tdr-loader.tdr-loading-on { display: flex !important; }
#loading.tdr-loader .loop { width: 80px !important; height: 80px !important; flex: 0 0 auto; }
@media (max-width: 640px) { #loading.tdr-loader .loop { width: 64px !important; height: 64px !important; } }
.spinning_loader img { display: none; }
/* legacy rotating icons (class .spin) keep turning; reduced motion slows them */
.spin { animation: loopSpin 1.2s linear infinite; }
.dot_animation::after { content: '…'; display: inline-block; animation: tdr-dots 1.2s steps(4, end) infinite; overflow: hidden; vertical-align: bottom; width: 0; }
@keyframes tdr-dots { to { width: 1.2em; } }
@media (prefers-reduced-motion: reduce) { .spin { animation-duration: 6s; } }

/* ================================================================================================================ */
/* 3. THE RUNTIME'S OWN UI                                                                                          */
/* ================================================================================================================ */

/* popups on <toddoo-dialog>: the look is the element's own; only widths, heights and padding are wired */
/* width: the content's own width, capped at the kit's wide modal (§10.14, .modal.wide: 640px). Legacy popup content is often
   "col s12" at 100%, which used to stretch the dialog to the viewport (1408–2207px, form audit F-27); wider content scrolls
   inside. Short messages stay narrow (fit-content, at least the compact 320px). */
@media (min-width: 640px) {
  toddoo-dialog.tdr-popup::part(dialog) { width: fit-content; max-width: min(var(--modal-w-lg), calc(100vw - var(--sp-8))); max-height: calc(100dvh - var(--sp-8)); min-width: min(var(--modal-w-sm), calc(100vw - var(--sp-8))); }
  toddoo-dialog.tdr-popup-window::part(dialog), toddoo-dialog.tdr-popup[size="lg"]::part(dialog) { width: min(var(--modal-w-lg), calc(100vw - var(--sp-8))); }
}
/* under 640px <toddoo-dialog> is the library's bottom sheet (R-29: full width, top corners rounded, counted in
   window.toddoo.sheet, so html[data-toddoo-sheet] hides the floating chrome); the runtime adds nothing there */
toddoo-dialog.tdr-popup::part(header) { padding-block: var(--sp-4) 0; padding-inline: var(--sp-6) var(--sp-4); }
toddoo-dialog.tdr-popup::part(body) { padding: 0 var(--modal-px) var(--modal-px); font-size: 13px; line-height: 1.5; overflow: auto; }
.tdr-popup-body { max-width: 100%; }
/* the native <dialog> fallback carries the kit's .modal.glass classes; here only what <dialog> needs on top */
dialog.tdr-popup-native { border: 0; max-width: min(var(--modal-w-lg), calc(100vw - var(--sp-8))); max-height: calc(100dvh - var(--sp-8)); overflow: auto; color: var(--text1); }
dialog.tdr-popup-native::backdrop { background: var(--modal-backdrop); }
.tdr-popup-x { position: absolute; top: var(--sp-2); right: var(--sp-2); z-index: 2; }
/* toasts: the fallback carries the kit's .toast classes; this is only the stack position */
#tdr-toasts { position: fixed; top: var(--sp-5); right: var(--sp-5); z-index: var(--z-toast); display: grid; gap: var(--toast-stack-gap); width: min(var(--toast-max-w), calc(100vw - var(--sp-10))); }
#tdr-toasts .toast { position: relative; padding-right: 44px; }
#tdr-toasts .toast-x { position: absolute; top: 4px; right: 4px; width: 36px; height: 36px; border: 0; border-radius: var(--radius-full); background: transparent; color: var(--text2); font-size: 20px; line-height: 1; cursor: pointer; }
#tdr-toasts .toast-x:hover { background: var(--accent-dim); color: var(--text1); }
#tdr-toasts .toast-x:focus-visible { outline: none; box-shadow: var(--focus-ring); }

/* selectors (§5.1, §5.2): the elements style themselves from the tokens */
/* min-height wins over any height, even an !important one from a widget rule (".swf_selector_container { height: 3vh
   !important }", www/widgets/exhibitor_company.php:847), so the library's trigger and its "+N" line are never squeezed */
.swf_selector_container { display: flex; flex-direction: column; gap: var(--sp-1); width: 100%; min-height: max-content; }
.swf_selector_list > :where(toddoo-select, toddoo-country-select) { min-height: var(--input-h); }
.swf_selector_label { font-size: 12px; font-weight: 500; color: var(--text2); }
.swf_selector_list { display: flex; align-items: center; gap: var(--sp-2); width: 100%; }
.swf_selector_list > toddoo-select { flex: 1 1 auto; min-width: 0; }
.swf_selector_icon { display: inline-flex; color: var(--text3); }
toddoo-select, toddoo-country-select { display: block; width: 100%; }

/* lists, filters, tags, toggles */
.tdr-filters { display: grid; gap: var(--sp-2); }
.tdr-filter-bar { flex-wrap: wrap; }
.tdr-filter { position: relative; }
.tdr-filter-btn { list-style: none; display: inline-flex; align-items: center; gap: var(--sp-2); min-height: var(--btn-h-sm); padding: 0 var(--btn-px-sm); border: var(--btn-border) solid var(--grey); border-radius: var(--radius-full); background: transparent; color: var(--grey); font-size: 11px; font-weight: 600; cursor: pointer; user-select: none; }
.tdr-filter-btn:hover { background: var(--grey); color: var(--on-accent); }
.tdr-filter-btn::-webkit-details-marker { display: none; }
.tdr-filter-btn::after { content: ''; width: 6px; height: 6px; border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor; transform: rotate(45deg) translateY(-2px); }
.tdr-filter-btn.active { border-color: var(--accent); color: var(--accent); background: transparent; }
/* the panel is the kit's .glass-elevated (set in 81-list.js; one level above the page, §10.5); here only size and layout.
   Width follows the content (so long labels do not wrap) within 260–380px; the list scrolls, the search box stays */
.tdr-filter-panel { position: absolute; z-index: var(--z-dropdown); top: calc(100% + var(--dd-offset)); left: 0; display: flex; flex-direction: column; gap: var(--sp-2); width: max-content; min-width: 260px; max-width: min(380px, calc(100vw - var(--sp-8))); max-height: calc(var(--dd-max-h) + 56px); overflow: auto; padding: var(--sp-2); border-radius: var(--dd-panel-radius); }
.tdr-filter-panel:not(.glass-elevated) { background: var(--surface); box-shadow: 0 0 0 1px var(--border); }
.tdr-filter-search { flex: none; width: 100%; }
.tdr-filter-list { flex: 1 1 auto; min-height: 0; max-height: var(--dd-max-h); overflow-y: auto; }
.tdr-filter-option { display: flex; align-items: center; gap: var(--sp-2); min-height: var(--dd-option-h); padding: 0 var(--sp-3); border: var(--dd-option-border) solid transparent; border-radius: var(--dd-option-radius); font-size: 13px; cursor: pointer; }
.tdr-filter-option[hidden] { display: none; }
/* phones: a bottom sheet, full width, up to 70% of the screen, 16px search (as the library's selects, R-19, AGENTS.md §17) */
@media (max-width: 639px) {
  .tdr-filter-panel { position: fixed; z-index: var(--z-sheet, 1100); top: auto; bottom: 0; left: 0; right: 0; width: 100vw; min-width: 0; max-width: 100vw; max-height: 70dvh; border-radius: var(--dd-panel-radius) var(--dd-panel-radius) 0 0; padding: var(--sp-3) var(--sp-3) calc(var(--sp-3) + env(safe-area-inset-bottom)); }
  .tdr-filter-list { max-height: none; }
  .tdr-filter-search input { font-size: 16px; }
  .tdr-filter-option { min-height: 44px; }
}
.tdr-filter-option:hover { background: var(--accent-dim); }
.tdr-filter-empty, .tdr-filter-loading { padding: var(--sp-2); font-size: 12px; color: var(--text2); }
.tdr-filter-chips { flex-wrap: wrap; }
/* Saved filters picker (11 Oct 2026): one row per saved filter, its name applies it, then Rename and Delete */
.tdr-saved-row { display: flex; align-items: center; gap: var(--sp-1); min-width: 0; }
.tdr-saved-use { flex: 1 1 auto; min-width: 0; border: 0; background: transparent; color: var(--text1); font: inherit; font-size: 13px; text-align: left; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tdr-saved-act { flex: none; min-height: 32px; padding: 0 var(--sp-2); border: 0; border-radius: var(--radius-full); background: transparent; color: var(--accent); font: inherit; font-size: 12px; font-weight: 600; cursor: pointer; }
.tdr-saved-act:hover { background: var(--accent-dim); }
.tdr-saved-act:focus-visible, .tdr-saved-use:focus-visible { outline: 0; box-shadow: var(--focus-ring); }
.tdr-saved-del { color: var(--red); }
@media (max-width: 639px) { .tdr-saved-act { min-height: 44px; } }
.tdr-chip-x { width: 18px; height: 18px; padding: 0; border: 0; border-radius: 50%; background: transparent; color: var(--text2); font-size: 14px; line-height: 1; cursor: pointer; }
.tdr-chip-x:hover { background: var(--teal); color: var(--on-accent); }
.flip_switch { display: inline-flex; align-items: center; gap: var(--sp-2); min-height: 28px; padding: 2px var(--sp-3) 2px 2px; border-radius: var(--radius-full); background: var(--border); color: var(--text1); font-size: 12px; font-weight: 600; cursor: pointer; transition: background-color var(--dur-medium); user-select: none; }
.flip_switch.active { background: var(--teal); color: var(--on-accent); }
.flip_switch_knob { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; border-radius: 50%; background: var(--surface); color: var(--text2); }
.flip_switch.active .flip_switch_knob { color: var(--teal); }
.flip_switch:focus-visible { box-shadow: var(--focus-ring); }
.tdr-toggle { display: inline-flex; padding: 2px; border-radius: var(--radius-full); background: var(--border); }
.tdr-toggle-option { flex: 1 1 0; min-height: 28px; padding: 0 var(--sp-3); border: var(--btn-border) solid transparent; border-radius: var(--radius-full); background: transparent; color: var(--text2); font-size: 12px; font-weight: 600; cursor: pointer; }
.tdr-toggle-option:hover { background: var(--accent-dim); }
.tdr-toggle-option[aria-checked="true"] { border-color: var(--accent); background: var(--surface); color: var(--accent); }
.tdr-created-by { font-size: 12px; }
.tdr-avatar { width: var(--avatar-sm); height: var(--avatar-sm); border-radius: 50%; object-fit: cover; flex: 0 0 auto; }
.tdr-avatar-initials { display: inline-flex; align-items: center; justify-content: center; background: var(--teal); color: var(--on-accent); font-size: 11px; font-weight: 600; }
.tile_library_item.selected { box-shadow: inset 0 0 0 1.5px var(--accent); }

/* stepper, bulk upload, dates */
.tdr-stepper { display: flex; align-items: flex-start; gap: 0; margin: 0; padding: 0; list-style: none; }
.tdr-step { position: relative; flex: 1 1 0; display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); text-align: center; }
.tdr-step.clickable { cursor: pointer; }
.step_circle { position: relative; z-index: 1; display: inline-flex; align-items: center; justify-content: center; width: var(--step-size); height: var(--step-size); border: var(--step-line) solid var(--step-upcoming-bg); border-radius: 50%; background: var(--surface); color: var(--text2); font-size: 13px; font-weight: 700; }
.tdr-step-done .step_circle { background: var(--step-done-bg); border-color: var(--step-done-bg); color: var(--step-done-text); }
.tdr-step-current .step_circle { background: var(--teal); border-color: var(--teal); color: var(--on-accent); box-shadow: var(--step-current-ring); }
.step_line_circle { position: absolute; top: calc(var(--step-size) / 2); left: calc(50% + 20px); right: calc(-50% + 20px); height: 0; }
.tdr-bulk-upload { display: grid; gap: var(--sp-3); min-width: min(480px, 80vw); }
.tdr-bulk-zone { display: block; }
.tdr-timerange { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--sp-3); }
/* the library's datetime field needs room for a date and a time side by side: 320px phase cards (one per row on phones) */
.tdr-timerange-fields { grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr)); }
.tdr-timerange-fields .tdr-timerange-head { display: flex; margin-bottom: var(--sp-1); }
.tdr-timerange-phase { padding: var(--sp-4); border: 1px solid var(--border); border-radius: var(--radius-xl); background: var(--surface); box-shadow: inset 0 var(--sp-1) 0 0 var(--phase-color, var(--teal)); }
.tdr-timerange-times { display: grid; gap: var(--sp-2); margin-top: var(--sp-2); }
.tdr-timerange-time { display: grid; gap: 2px; }
.tdr-daterange { display: grid; gap: var(--sp-2); padding: var(--sp-3); border-radius: var(--radius-xl); }
.tdr-daterange-row { display: grid; grid-template-columns: minmax(80px, 140px) 1fr auto; align-items: center; gap: var(--sp-3); }
.tdr-daterange-track { position: relative; height: var(--prog-track-h); border-radius: var(--prog-radius); background: var(--prog-track-bg); }
.tdr-daterange-bar { position: absolute; top: 0; bottom: 0; border-radius: var(--prog-radius); }
/* the calendar keeps the kit's size (§10.12: 300px wide, 40px day cells) even in a narrow legacy column: it never shrinks
   below 7 cells; on a phone the column scrolls sideways instead of crushing it (form audit F-16; the kit picker is R-20) */
.tdr-calendar { flex: none; width: var(--cal-w); min-width: calc(7 * var(--cal-cell)); max-width: 100%; }
/* a legacy grid row that holds a calendar (bookings: the calendar sits in a "col s1", 8%): the calendar's column takes the
   calendar's width and the other column the rest, instead of the calendar spilling over the list; on phones they stack */
.row:has(> .col > :is(.tdr-calendar, .tdr-date-single), > .col > * > :is(.tdr-calendar, .tdr-date-single)) { display: flex; align-items: flex-start; gap: var(--sp-4); }
.row:has(> .col > :is(.tdr-calendar, .tdr-date-single), > .col > * > :is(.tdr-calendar, .tdr-date-single))::after { display: none; }
.row:has(> .col > :is(.tdr-calendar, .tdr-date-single), > .col > * > :is(.tdr-calendar, .tdr-date-single)) > .col { float: none; }
.row:has(> .col > :is(.tdr-calendar, .tdr-date-single), > .col > * > :is(.tdr-calendar, .tdr-date-single)) > .col:has(> :is(.tdr-calendar, .tdr-date-single), > * > :is(.tdr-calendar, .tdr-date-single)) { flex: 0 0 calc(var(--cal-w) + var(--sp-4)); width: auto; min-width: 0; }
.row:has(> .col > :is(.tdr-calendar, .tdr-date-single), > .col > * > :is(.tdr-calendar, .tdr-date-single)) > .col:not(:has(> :is(.tdr-calendar, .tdr-date-single), > * > :is(.tdr-calendar, .tdr-date-single))) { flex: 1 1 0; width: auto; min-width: 0; }
@media (max-width: 639px) {
  .row:has(> .col > :is(.tdr-calendar, .tdr-date-single), > .col > * > :is(.tdr-calendar, .tdr-date-single)) { flex-wrap: wrap; }
  .row:has(> .col > :is(.tdr-calendar, .tdr-date-single), > .col > * > :is(.tdr-calendar, .tdr-date-single)) > .col { flex-basis: 100%; }
}
.tdr-cal-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.tdr-cal-head .btn { width: var(--cal-nav-size); height: var(--cal-nav-size); }
.tdr-cal-title { flex: 1 1 auto; min-width: 0; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-weight: 600; }
.tdr-cal-grid { display: grid; grid-template-columns: repeat(7, var(--cal-cell)); justify-content: space-between; row-gap: var(--sp-1); margin-top: var(--sp-2); text-align: center; }
.tdr-cal-dow { color: var(--text3); font-size: 10px; font-weight: 600; line-height: 24px; }
.tdr-cal-day { width: var(--cal-cell); height: var(--cal-cell); padding: 0; border: 1.5px solid transparent; border-radius: var(--cal-cell-radius); background: transparent; color: var(--text1); font-size: 13px; cursor: pointer; }
.tdr-cal-day:hover:not(:disabled) { color: var(--focus-color); }
.tdr-cal-day.today { border: var(--cal-today-border); }
.tdr-cal-day.selected { background: var(--cal-selected-bg); color: var(--cal-selected-text); font-weight: 600; }
/* unavailable days: --text3 only (with opacity on top they were nearly invisible, F-16) */
.tdr-cal-day:disabled { color: var(--text3); cursor: default; }
.tdr-drag-scroll { overflow-x: auto; cursor: grab; }
.tdr-drag-scroll.dragging { cursor: grabbing; user-select: none; }

/* full-page message (empty-state rules, §10.14) */
/* one card in the middle (design "EA console — no access", 6 Oct 2026) */
.tdr-redirect { position: fixed; inset: 0; z-index: var(--z-modal); display: flex; align-items: center; justify-content: center; padding: 48px 16px; box-sizing: border-box; overflow-y: auto; background: var(--bg); }
.tdr-redirect-card { width: 100%; max-width: 480px; margin: auto; padding: 40px 32px 32px; box-sizing: border-box; display: flex; flex-direction: column; align-items: center; gap: 16px; text-align: center; }
/* the library logotype (.logo: the kit sets colour, aspect ratio and the 100px minimum); only the width here (§11.5: 100–120px) */
.tdr-redirect-logo { width: 110px; }
.tdr-redirect-ico { width: 64px; height: 64px; margin-top: 8px; border-radius: 50%; background: var(--accent-dim); color: var(--teal); display: flex; align-items: center; justify-content: center; }
.tdr-redirect-title { margin: 0; font-size: 22px; font-weight: 600; line-height: 1.35; color: var(--text1); }
.tdr-redirect-msg { max-width: var(--empty-max-w); margin: 0; font-size: 14px; line-height: 1.6; color: var(--text2); overflow-wrap: anywhere; }
.tdr-redirect-msg strong { color: var(--text1); }
.tdr-redirect-count { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 8px 12px; padding: 10px 16px; border-radius: 24px; background: var(--accent-dim); font-size: 13px; color: var(--text1); font-variant-numeric: tabular-nums; }
.tdr-redirect-count .loop { width: 16px; height: 16px; }
.tdr-redirect-actions { display: flex; flex-direction: column; gap: 8px; width: 100%; margin-top: 8px; }
.tdr-redirect-actions .btn { width: 100%; min-height: 44px; justify-content: center; box-sizing: border-box; }
.tdr-redirect-stay { min-height: 44px; }
.tdr-redirect-foot { margin: 8px 0 0; font-size: 12px; color: var(--text2); }
.tdr-redirect-foot a { color: var(--teal); font-weight: 600; text-decoration: none; display: inline-flex; align-items: center; min-height: 44px; }
.tdr-redirect-foot a:hover { text-decoration: underline; }
@media (max-width: 480px) { .tdr-redirect-card { padding: 32px 20px 24px; } }

/* rich text shown by trumbowyg_build */
.trumbowyged.component-editor-content { overflow-wrap: anywhere; line-height: 1.6; }
.trumbowyged.component-editor-content p { margin: 0 0 var(--sp-2); }
.trumbowyged.component-editor-content a { color: var(--teal); text-decoration: underline; }
.swf_component_editor { display: block; width: 100%; }


/* ================================================================================================================ */
/* 4. RESPONSIVE (AGENTS.md §17): what the runtime can fix without touching widget markup. Breakpoints: mobile 0–639px. */
/* ================================================================================================================ */
/* touch screens: tap areas of at least 44×44 (§15, §17). The library gives its own classes and components one (.btn, .tab,
   .pg-btn, .sidebar-item, every component control; 44px .toggle/.check/.radio rows; 16px .inp on phones: R-25, R-30), so
   only LEGACY markup the library does not style is covered here, the same way: an invisible ::after reaching 44px, so the
   control keeps its look (legacy .but buttons, Materialize .btn-small/.btn-floating, the portal top-bar icons and profile,
   the rail items). data-nohit opts out, as in the library. */
@media (pointer: coarse), (max-width: 639px) {
  :where(.but, .btn-small, .btn-floating, .tdr-cal-day):not([data-nohit]),
  .toddoo-runtime :where(.icon_topbar, .tdo-menu, .back_portal_menu, .profile_exhibitor, .profile_ea, .profile_organiser):not([data-nohit]),
  :where(.toddoo-runtime :is(#top_bar_cube, #header_cube) :is([onclick], a[href]):not([data-nohit])) { position: relative; }   /* zero specificity: a widget's own position wins */
  :where(.but, .btn-small, .btn-floating, .tdr-cal-day):not([data-nohit])::after,
  .toddoo-runtime :where(.icon_topbar, .tdo-menu, .back_portal_menu, .profile_exhibitor, .profile_ea, .profile_organiser):not([data-nohit])::after,
  .toddoo-runtime :where(#top_bar_cube, #header_cube) :where([onclick], a[href]):not([data-nohit])::after {
    content: ""; position: absolute;
    top: min(0px, calc((100% - 44px) / 2)); bottom: min(0px, calc((100% - 44px) / 2));
    left: min(0px, calc((100% - 44px) / 2)); right: min(0px, calc((100% - 44px) / 2));
  }
}
@layer toddoo-runtime-base {
  /* phones: 16px in fields so iOS does not zoom on focus (§17) */
  @media (max-width: 639px) {
    input:not([type=checkbox], [type=radio]), select, textarea { font-size: 16px; }
    /* title-and-action rows (space-between) wrap instead of pushing the action off the card */
    .valign_wrapper_between, .flex_container_between { flex-wrap: wrap; row-gap: var(--sp-2); }
  }
}
@media (max-width: 639px) {
  /* portal top bars (#top_bar_cube > .row > .col…, float columns of a third each): one flex row; texts truncate instead of
     running into each other; the profile keeps its picture, not its name */
  .toddoo-runtime #top_bar_cube > .row { display: flex; align-items: center; gap: var(--sp-2); }
  .toddoo-runtime #top_bar_cube > .row > .col { float: none; flex: 0 1 auto; width: auto; min-width: 0; padding: 0; overflow: hidden; }
  .toddoo-runtime #top_bar_cube > .row > .col:nth-child(2):not(:last-child) { flex: 1 1 0; }
  /* the last column (icons, profile, event switcher) keeps its size; a wide control in it truncates instead */
  .toddoo-runtime #top_bar_cube > .row > .col:last-child { flex: 0 0 auto; max-width: 62vw; }
  .toddoo-runtime #top_bar_cube > .row > .col:last-child > * { flex: none; }
  .toddoo-runtime #top_bar_cube > .row > .col:last-child > :not(.icon_topbar, .valign_wrapper, [class*="profile"]) { flex: 0 1 auto; max-width: 38vw; overflow: hidden; }
  .toddoo-runtime #top_bar_cube > .row > .col :where(div, span, button, a):not(.icon_topbar, .counter_circle, .mini_profile_image) { min-width: 0; max-width: 100%; }
  .toddoo-runtime #top_bar_cube > .row > .col img { flex: none; }
  .toddoo-runtime #top_bar_cube > .row > .col :where(.h4, .h5, .h6, span:not(.counter_circle)) { display: block; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; max-width: 100%; }
  .toddoo-runtime #top_bar_cube > .row > .col :where(.profile_exhibitor, .profile_ea, .profile_organiser) { width: auto; flex: none; }
  .toddoo-runtime #top_bar_cube > .row > .col :where(.profile_exhibitor, .profile_ea, .profile_organiser) :where(span, .h5, .h6, svg) { display: none; }
  .toddoo-runtime #top_bar_cube > .row > .col .icon_topbar { flex: none; }
  /* the icon rail inside the library's drawer (<toddoo-sidebar class="tdr-rail">, wrapped at mount by 87-responsive.js; the
     drawer itself, its glass, button, backdrop and focus trap are the library's): the rail fills the 280px drawer as a text
     sidebar (§10.13 text mode), each item an icon + its name (the markup carries the stored name in data-menu="…") */
  toddoo-sidebar.tdr-rail .organiser_menu, toddoo-sidebar.tdr-rail #menu_exhibitor_cube { width: 100%; padding: 0; row-gap: var(--sp-1); background: transparent; box-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none; }
  toddoo-sidebar.tdr-rail .tdo-menu { justify-content: flex-start; gap: var(--sp-3); width: 100%; max-width: none; height: 44px; max-height: none; padding: 0 var(--sb-item-px, 14px); border-radius: var(--radius-full); }
  toddoo-sidebar.tdr-rail .tdo-menu::before { content: attr(data-menu); order: 2; font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  toddoo-sidebar.tdr-rail .tdo-menu-text { display: none; }
  /* sub-menus with an inline narrow width (the organiser's event menu: #exhibition_menu, width: 3.5vh) widen with the drawer:
     min-width wins over an inline width without !important */
  toddoo-sidebar.tdr-rail :where(#exhibition_menu, .extra_menu) { min-width: 100%; }
}
/* while a bottom sheet is open (<html data-toddoo-sheet="n">: the library's selects, and the runtime's filter sheet), the
   floating chrome at the bottom of the screen steps aside: the app's hold counter (#hold_fab_container, fixed, z 9999)
   hides (the library's own menu button is the library's), and a bottom toast stack moves to the top so it never covers the sheet's rows */
html[data-toddoo-sheet] #hold_fab_container { visibility: hidden; pointer-events: none; }
html[data-toddoo-sheet] toddoo-toaster:not([position^="top"]) { top: var(--sp-4); bottom: auto; }
