﻿/* TBevel */
/* TBevel — a 3D divider/frame (real VCL TBevel). NO Brush/Pen/border-width: the bevel is entirely the
   Shape x Style classes below (CSS inset/outset/groove/ridge derive their light/dark edges from the border
   colour, giving the classic VCL sunken/raised look). VCL enum values (bsBox/bsFrame/bs*Line/bsSpacer x
   bsLowered/bsRaised) are used as-is (we keep the true VCL prop/enum names). */
.vcl-bevel { box-sizing: border-box; }

/* bsBox — full border. bsLowered = sunken, bsRaised = popped-out. */
.vcl-bevel-bsBox.vcl-bevel-bsLowered     { border: 2px inset  #c0c0c0; }
.vcl-bevel-bsBox.vcl-bevel-bsRaised      { border: 2px outset #c0c0c0; }
/* bsFrame — a double-bevelled groove/ridge. */
.vcl-bevel-bsFrame.vcl-bevel-bsLowered   { border: 2px groove #c0c0c0; }
.vcl-bevel-bsFrame.vcl-bevel-bsRaised    { border: 2px ridge  #c0c0c0; }
/* single-edge lines */
.vcl-bevel-bsTopLine.vcl-bevel-bsLowered     { border-top: 2px groove #c0c0c0; }
.vcl-bevel-bsTopLine.vcl-bevel-bsRaised      { border-top: 2px ridge  #c0c0c0; }
.vcl-bevel-bsBottomLine.vcl-bevel-bsLowered  { border-bottom: 2px groove #c0c0c0; }
.vcl-bevel-bsBottomLine.vcl-bevel-bsRaised   { border-bottom: 2px ridge  #c0c0c0; }
.vcl-bevel-bsLeftLine.vcl-bevel-bsLowered    { border-left: 2px groove #c0c0c0; }
.vcl-bevel-bsLeftLine.vcl-bevel-bsRaised     { border-left: 2px ridge  #c0c0c0; }
.vcl-bevel-bsRightLine.vcl-bevel-bsLowered   { border-right: 2px groove #c0c0c0; }
.vcl-bevel-bsRightLine.vcl-bevel-bsRaised    { border-right: 2px ridge  #c0c0c0; }
/* bsSpacer — invisible spacer (no border) */

/* TBitBtn */
/* TBitBtn — a push button with an optional bitmap glyph + a Kind preset (real VCL TBitBtn, parent TCustomButton).
   Renders its Caption; geometry/Font from the inline {Style}. Kind (bkOK/bkCancel/...), Default, Cancel, Glyph are
   carried as real VCL props (the standard Kind glyph is later polish). VCL prop names kept verbatim. */
.vcl-bitbtn {
  cursor: pointer;
  border: 1px solid #adadad;
  border-radius: 3px;
  background: linear-gradient(to bottom, #f5f5f5, #dcdcdc);
  color: #1a1a1a;
  font: 11px Tahoma, sans-serif;
  box-sizing: border-box;
}
.vcl-bitbtn:hover  { background: linear-gradient(to bottom, #e8f0fe, #c2d4f8); border-color: #4a7abf; }
.vcl-bitbtn:active { background: linear-gradient(to bottom, #c2d4f8, #e8f0fe); }

/* TColorBox */
/* TColorBox — a color-picker combobox (real VCL TColorBox, parent TCustomComboBox). Renders a closed combobox: a
   swatch of the Selected colour (painted via the --sel CSS var set by ColorVarCss in compPackageUnit) + the colour
   name + a drop arrow. Style (the cb* set of which colour groups appear) is carried as a real VCL prop. VCL names kept. */
.vcl-colorbox {
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 0 4px;
  background: #fff;
  border: 1px solid rgb(173, 173, 173);
  font: 11px Tahoma, sans-serif;
  box-sizing: border-box;
}
.vcl-colorbox-sw    { width: 14px; height: 14px; border: 1px solid #888; background: var(--sel, #000); flex: 0 0 auto; }
.vcl-colorbox-cap   { flex: 1 1 auto; overflow: hidden; white-space: nowrap; }
.vcl-colorbox-arrow { flex: 0 0 auto; color: #555; }

/* TColorListBox */
/* TColorListBox — a list of colour swatches (real VCL TColorListBox, parent TCustomListBox). Design-time preview: the
   Selected colour row (swatch via the --sel CSS var from ColorVarCss) plus a few representative standard colours.
   Style (the cb* set) is carried as a real VCL prop; the live colour set is a runtime concern. VCL names kept. */
.vcl-colorlistbox {
  background: #fff;
  border: 1px solid rgb(173, 173, 173);
  font: 11px Tahoma, sans-serif;
  box-sizing: border-box;
  overflow: hidden;
}
.vcl-clb-row    { display: flex; align-items: center; gap: 4px; padding: 1px 3px; height: 16px; }
.vcl-clb-sel    { background: #3399ff; color: #fff; }
.vcl-clb-row .vcl-swatch { width: 12px; height: 12px; border: 1px solid #888; flex: 0 0 auto; }

/* TFlexPanel */
.vcl-flexpanel {
  box-sizing: border-box;
  display: flex;
}

/* TFlowPanel */
/* TFlowPanel — a real VCL TFlowPanel: a panel that AUTO-FLOWS its children. We map its real VCL FlowStyle/AutoWrap
   onto the granted flex layout exception in LayoutCssFromDfm (compPackageUnit) BY CLASS (display:flex + direction +
   wrap), so children become flex items (FlexItemStyle). The background/border is the panel face; geometry comes from
   the inline {Style}. VCL prop/enum names kept verbatim (FlowStyle fs*, AutoWrap). */
.vcl-flowpanel {
  background: #f0f0f0;
  border: 1px solid #d0d0d0;
  box-sizing: border-box;
}

/* TGridPanel */
/* TGridPanel — a real VCL TGridPanel: a panel that lays children in a grid (ColumnCollection x RowCollection).
   We map its real VCL ColumnCount/RowCount onto the granted grid layout exception in LayoutCssFromDfm (compPackageUnit)
   BY CLASS (display:grid + grid-template-columns/rows: repeat(N,1fr)), so children become grid items (GridItemStyle,
   auto-placed cell by cell). Geometry comes from the inline {Style}. VCL prop names kept verbatim. */
.vcl-gridpanel {
  background: #f0f0f0;
  border: 1px solid #d0d0d0;
  box-sizing: border-box;
}

/* TImage */
/* TImage — a real VCL TImage. The Picture (a base64 'data:image/png;base64,...' URI held in the Picture prop) paints
   as a CSS background-image via the inline {Style} (ImageCssFromDfm); Stretch/Proportional/Center map to
   background-size/position. No backdrop fill — like the VCL control (and the reference <img>) it is transparent; an
   empty Picture shows a dashed placeholder (emitted inline by ImageCssFromDfm). VCL prop/enum names kept verbatim
   (stay true VCL — Picture/Stretch/Proportional/Center/AutoSize/Transparent). */
.vcl-image { box-sizing: border-box; background-repeat: no-repeat; background-position: center; }

/* TMaskEdit */
/* TMaskEdit — a masked text edit (real VCL TMaskEdit, parent TCustomMaskEdit). Renders an <input> showing Text; the
   EditMask is surfaced as the placeholder hint. MaxLength/ReadOnly/BorderStyle are carried as real VCL props. VCL
   prop names kept verbatim. */
.vcl-maskedit {
  background: #fff;
  border: 1px solid rgb(173, 173, 173);
  font: 11px Tahoma, sans-serif;
  box-sizing: border-box;
}

/* TPaintBox */
/* TPaintBox — a blank owner-drawn canvas (real VCL TPaintBox, parent TGraphicControl). It has no content of its own
   (the app paints it at runtime via OnPaint), so at design time we show an empty box with a faint hatch + border so
   the surface is visible/selectable. Geometry/Font come from the inline {Style}. VCL prop names kept verbatim. */
.vcl-paintbox {
  box-sizing: border-box;
  border: 1px solid #c0c0c0;
  background: repeating-linear-gradient(45deg, transparent, transparent 6px, rgba(0,0,0,0.04) 6px, rgba(0,0,0,0.04) 7px);
}

/* TShape */
/* TShape — a styled box (real VCL TShape). The fill (Brush.Color) + outline (Pen.Color/Width/Style) come from the
   inline {Style} (ShapeCssFromDfm); the Shape prop only picks the corner rounding via the class below. VCL enum
   values (st*) kept as-is (stay on true VCL). */
.vcl-shape { box-sizing: border-box; }
.vcl-shape-stRoundRect,
.vcl-shape-stRoundSquare { border-radius: 8px; }
.vcl-shape-stEllipse,
.vcl-shape-stCircle      { border-radius: 50%; }
/* stRectangle / stSquare: square corners (no radius) */

/* TSpeedButton */
/* TSpeedButton — a compact flat/group button (real VCL TSpeedButton, parent TGraphicControl). Renders its Caption;
   geometry/Font come from the inline {Style}. Flat/Down/GroupIndex/AllowAllUp are carried as real VCL props (visual
   pressed/flat states are later polish). VCL prop names kept verbatim (stay true VCL). */
.vcl-speedbutton {
  cursor: pointer;
  border: 1px solid #adadad;
  border-radius: 2px;
  background: linear-gradient(to bottom, #f5f5f5, #e4e4e4);
  color: #1a1a1a;
  font: 11px Tahoma, sans-serif;
  padding: 0;
  box-sizing: border-box;
}
.vcl-speedbutton:hover  { background: linear-gradient(to bottom, #e8f0fe, #c2d4f8); border-color: #4a7abf; }
.vcl-speedbutton:active { background: linear-gradient(to bottom, #c2d4f8, #e8f0fe); }

/* TSplitter */
/* TSplitter — a draggable pane divider (real VCL TSplitter, parent TCustomControl). A thin bar painted in the panel
   face colour with a resize cursor. Align/MinSize/ResizeStyle/Beveled are carried as real VCL props (the actual drag
   resize is a runtime concern). VCL prop names kept verbatim. */
.vcl-splitter {
  background: #f0f0f0;
  box-sizing: border-box;
  cursor: col-resize;
}

/* TYouTube */
/* TYouTube — host carries the geometry (inline {Style}). On /design (no client.js) the dark
   placeholder below is shown (the HTML analogue of the reference's GDI preview panel: dark box +
   red play button + "YouTube" + the video id). At runtime client.js replaces the inner content with
   the actual <iframe> embed. */

.vcl-youtube {
  box-sizing: border-box;
  position: relative;
  overflow: hidden;
  background: #1a1a1a;
  border: 0;
}
.vcl-youtube > iframe { display: block; width: 100%; height: 100%; border: 0; }

/* design-time placeholder */
.vcl-youtube-ph {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  font-family: Tahoma, "Segoe UI", sans-serif;
  user-select: none;
}
.vcl-youtube-play { display: block; filter: drop-shadow(0 1px 2px rgba(0,0,0,.4)); }
.vcl-youtube-brand { color: #ffffff; font-size: 13px; font-weight: bold; letter-spacing: .3px; }
.vcl-youtube-id { color: #aaaaaa; font-size: 11px; max-width: 92%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.vcl-youtube-id:empty::before { content: "(no video)"; color: #777777; }

/* TAudioPlayer */
/* TAudioPlayer — verbatim from the reference styles/classic.css (.vcl-audio*). A card with a hidden
   <audio> + a custom UI: title + clock, play button, seek timeline, mute/loop toggles, volume slider.
   client.js (ported wireAudioPlayer) drives playback + updates the timeline/labels and fires events. */

.vcl-audio {
  box-sizing: border-box; display: flex; flex-direction: column; justify-content: center;
  gap: 6px; padding: 8px 10px; background: #f5f6f8; border: 1px solid #c2c7d0; border-radius: 4px;
  font: 12px Tahoma, sans-serif; color: #333; -webkit-user-select: none; user-select: none;
}
.vcl-audio-el { display: none; }
.vcl-audio-top { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.vcl-audio-title { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; font-weight: bold; }
.vcl-audio-clock { flex: 0 0 auto; color: #666; white-space: nowrap; font-variant-numeric: tabular-nums; }
.vcl-audio-dur { cursor: pointer; }   /* click toggles total <-> remaining */
.vcl-audio-row { display: flex; align-items: center; gap: 8px; }
.vcl-audio-play {
  flex: 0 0 auto; width: 26px; height: 26px; padding: 0; box-sizing: border-box;
  border: 1px solid #8a90a0; border-radius: 50%; background: #fff; color: #333; cursor: pointer;
  display: flex; align-items: center; justify-content: center; font-size: 12px; line-height: 1;
}
.vcl-audio-play:hover { background: #eef1f6; }
.vcl-audio-play::before { content: '\25B6'; }                      /* play triangle */
.vcl-audio--playing .vcl-audio-play::before { content: '\23F8'; }  /* pause bars */
.vcl-audio-seek {
  position: relative; flex: 1 1 auto; height: 16px; cursor: pointer; touch-action: none; outline: none;
}
.vcl-audio-seek:focus-visible { outline: 1px dotted #888; }
.vcl-audio-groove { position: absolute; left: 7px; right: 7px; top: 50%; height: 4px;
  transform: translateY(-50%); background: #d9dde4; border: 1px solid #b0b6c0; box-sizing: border-box; }
.vcl-audio-fill { position: absolute; left: 7px; top: 50%; height: 4px; width: 0;
  transform: translateY(-50%); background: #3b82f6; }
.vcl-audio-thumb { position: absolute; top: 50%; left: 7px; width: 10px; height: 14px;
  transform: translate(-50%, -50%); background: #fff; border: 1px solid #5a6270; border-radius: 2px; }
.vcl-audio-mute, .vcl-audio-loop {
  flex: 0 0 auto; width: 24px; height: 22px; padding: 0; box-sizing: border-box;
  border: 1px solid #b0b6c0; border-radius: 3px; background: #fff; color: #444; cursor: pointer;
  display: flex; align-items: center; justify-content: center; font-size: 12px; line-height: 1;
}
.vcl-audio-mute:hover, .vcl-audio-loop:hover { background: #eef1f6; }
.vcl-audio-mute::before { content: '\1F50A'; }                    /* speaker */
.vcl-audio--muted .vcl-audio-mute::before { content: '\1F507'; }  /* muted speaker */
.vcl-audio-loop::before { content: '\1F501'; }                    /* repeat */
.vcl-audio--loop .vcl-audio-loop { background: #e7f0ff; border-color: #3b82f6; color: #1d4ed8; }
.vcl-audio-vol { position: relative; flex: 0 0 56px; height: 16px; cursor: pointer; touch-action: none; outline: none; }
.vcl-audio-vol:focus-visible { outline: 1px dotted #888; }

/* TContentSlot */
/* TContentSlot — a DESIGN-TIME marker only. It shows where a page's own body is
   spliced in when the page uses this form as its layout. It is REMOVED from the
   composed page at render/export time (formRendererUnit.ComposePageForm), so the
   running app never paints it — these styles are seen only on the layout's
   design canvas. */
.vcl-contentslot{
  box-sizing:border-box;
  display:flex; align-items:center; justify-content:center;
  border:2px dashed #9aa7bd; border-radius:8px;
  background:repeating-linear-gradient(45deg,#f5f7fb,#f5f7fb 12px,#eef2f8 12px,#eef2f8 24px);
  color:#5b6b86; font-family:Tahoma,sans-serif; overflow:hidden;
}
.vcl-contentslot .tp-slot-marker{ text-align:center; pointer-events:none; }
.vcl-contentslot .tp-slot-title{ font-size:15px; font-weight:600; letter-spacing:.3px; }
.vcl-contentslot .tp-slot-sub{ font-size:11px; opacity:.7; margin-top:4px; }
/* v476: design-time placeholder text moved out of template.html (it used to ship into every exported
   page) into CSS-generated content scoped to the design canvas. See TScrollStory/styles.css. */
.tp-design .vcl-contentslot .tp-slot-title::before{ content:'Page content'; }
.tp-design .vcl-contentslot .tp-slot-sub::before{ content:'each page using this layout renders its own body here'; }

/* TFileDrop */
.vcl-filedrop {
  box-sizing: border-box;
  border: 2px dashed #a0a0a0;
  background: #fafafa;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #808080;
  font: 12px Tahoma, sans-serif;
  text-align: center;
}

/* TFooter */
.vcl-footer {
  box-sizing: border-box;
  border-top: 1px solid #d0d0d0;
  background: #f7f7f7;
  display: flex;
  align-items: center;
  padding: 4px 8px;
  font: 11px Tahoma, sans-serif;
  color: #444;
}

/* TGemini */
/* TGemini is a NON-VISUAL component: it uses the shared .vcl-nonvisual puck (display:none at runtime,
   revealed at design by ServeDesign; the instance name is the ::after label — both rules come from
   components/Data/TMySQLDatabase/styles.css via /components.css). Here we override only the puck GLYPH
   with a Gemini "spark" badge. The element still exists (hidden) at runtime so SendPrompt can target it. */

.vcl-nonvisual.vcl-gemini {
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Crect x='.5' y='.5' width='23' height='23' rx='5' fill='%234285F4'/%3E%3Cpath d='M12 4c.4 3.4 1.2 4.2 4.6 4.6C13.2 9 12.4 9.8 12 13.2 11.6 9.8 10.8 9 7.4 8.6 10.8 8.2 11.6 7.4 12 4z' fill='%23ffffff'/%3E%3Cpath d='M16.5 13c.2 1.7.6 2.1 2.3 2.3-1.7.2-2.1.6-2.3 2.3-.2-1.7-.6-2.1-2.3-2.3 1.7-.2 2.1-.6 2.3-2.3z' fill='%23ffffff' opacity='.85'/%3E%3C/svg%3E") center / 24px 24px no-repeat;
}

/* THeader */
/* THeader (W) -- .vcl-header bar chrome. client.js builds the DOM + inline-styles the .vcl-popup-menu
   dropdowns (appended to <body>) + toggles the collapse classes. Runtime only (hidden at /design). */

/* v376 (port tsw2 v305): chrome colour literals flow through --tp-* theme tokens (fallbacks = pre-v376
   literals -> classic pixel-identical). The comp's own --hdr-* runtime vars (set inline by client.js from
   props) and the semantic error red are left as-is. */
.vcl-header { box-sizing:border-box; display:flex; align-items:center; gap:12px; width:100%; min-height:var(--hdr-h,64px); padding:0 16px; background:var(--tp-surface-2,#f0f0f0); border-bottom:1px solid var(--tp-border,#888); font:12px Tahoma,sans-serif; color:var(--tp-fg,#333); overflow:hidden; -webkit-user-select:none; user-select:none; }
.vcl-header--sticky { position:sticky; top:0; z-index:50; }
.vcl-header--noborder { border-bottom:none; }
.vcl-header--menu-left { gap:0; }
.vcl-header--menu-left .vcl-header-menu { margin-left:35px; }
.vcl-header-brand { display:flex; align-items:center; gap:10px; flex:0 0 auto; min-width:0; }
.vcl-header-logo { max-height:calc(var(--hdr-h,64px) - 20px); max-width:220px; height:auto; width:auto; object-fit:contain; display:block; }
.vcl-header-text { display:flex; flex-direction:column; justify-content:center; line-height:1.15; min-width:0; }
.vcl-header-title { font-weight:bold; font-size:1.25em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.vcl-header-subtitle { font-size:0.85em; opacity:0.72; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.vcl-header-menu { display:flex; align-items:stretch; gap:2px; margin-left:auto; flex:0 1 auto; min-width:0; overflow:hidden; }
.vcl-header-mi { padding:3px 12px 6px; display:flex; align-items:center; cursor:pointer; white-space:nowrap; flex:0 0 auto; }  /* v401 (tsw2 v331): taller hover-highlight box (+3px top / +6px bottom) */
.vcl-header-mi:hover { background:var(--tp-hover,rgba(0,0,0,0.06)); }
/* v445 (tsw2 v375): active-nav marker -- an underline bar on the item whose url IS the current page ("you are here").
   inset box-shadow = zero layout shift (a border would change the item box); currentColor follows the
   menu font color, so it adapts to themes and the invert-hover variant with no extra rules. */
.vcl-header-mi--current { box-shadow:inset 0 -2px 0 currentColor; }
.vcl-header-mi--disabled { color:var(--tp-fg-muted,#999); cursor:default; }
.vcl-header-mi--disabled:hover { background:none; }
.vcl-header--invert-sel .vcl-header-menu .vcl-header-mi:not(.vcl-header-mi--disabled):hover { background:var(--hdr-menu-color,currentColor); color:var(--hdr-bg,#f0f0f0); }
.vcl-header--banner .vcl-header-title, .vcl-header--banner .vcl-header-subtitle { text-shadow:0 1px 2px rgba(0,0,0,0.45); }

.vcl-header-btns { display:flex; align-items:stretch; flex:0 0 auto; }
.vcl-header-btn { display:flex; align-items:center; justify-content:center; box-sizing:border-box; width:30px; align-self:stretch; padding:0 5px; background:none; border:none; cursor:pointer; color:inherit; flex:0 0 auto; }
.vcl-header-btn:hover { background:var(--tp-hover,rgba(0,0,0,0.06)); }
.vcl-header-btn svg { width:18px; height:18px; display:block; }
.vcl-header--collapsed .vcl-header-btns { display:none; }

.vcl-header-burger { display:none; box-sizing:border-box; width:34px; height:26px; padding:5px 6px; flex-direction:column; justify-content:space-between; align-items:stretch; background:none; border:none; cursor:pointer; color:inherit; flex:0 0 auto; }
.vcl-header-burger span { display:block; height:2px; background:currentColor; border-radius:1px; }
.vcl-header--collapsed .vcl-header-menu { display:none; }
.vcl-header--collapsed .vcl-header-burger { display:flex; position:absolute; left:16px; top:50%; transform:translateY(-50%); }
/* v448 (port tpwebide/styles/classic.css:1612-1615, rule #2): on collapse the burger goes position:absolute at
   left:16px -- OUT of the flex flow -- but the in-flow brand still began at the header's own padding-left:16px, so
   the burger painted straight on top of the title. The reference CENTERS the brand when collapsed (burger owns the
   left inset, login the right), which clears it; W had never ported these two rules.
   position:relative makes the HEADER the burger's containing block. Without it the absolute burger resolves against
   the nearest positioned ancestor -- the form body is position:relative -- and escapes the header entirely (its
   top:50% would centre it on the whole FORM). Sticky is already a containing block, so don't override its position:
   the reference's exact :not() guard.
   OMITTED from the reference block, per "adapt only what our backend forces": its TopMenu variants
   (.vcl-header--has-topmenu / .vcl-header-row2 / --hdr-base-h) -- W dropped TopMenu at v234 ("main hierarchical Menu
   only") and emits neither class, so the reference's :not(.vcl-header--has-topmenu) qualifier is always true here and
   is folded away. Its `.vcl-header-brand { margin-left/right:0 !important }` reset is omitted too: that exists to
   defeat the reference's INLINE lpPage/tpPage page-inset margin on the brand, and W's client.js brand() sets no
   inline margin (--hdr-page-inset is READ by the login only, never set anywhere in W). */
.vcl-header--collapsed { justify-content:center; }
.vcl-header--collapsed:not(.vcl-header--sticky) { position:relative; }

/* v367 (tsw2 v296): the login widget -- bar button (icon; name+icon when signed in) + the sign-in panel
   (appended to <body>). The two tsw2 rules coupling login to the SEARCH button are omitted (W has no search). */
.vcl-header-login { display:flex; align-items:center; justify-content:center; box-sizing:border-box; width:34px; align-self:stretch; padding:0 6px; background:none; border:none; cursor:pointer; color:inherit; flex:0 0 auto; margin-right:var(--hdr-page-inset,0px); }
.vcl-header-login:hover { background:var(--tp-hover,rgba(0,0,0,0.06)); }
.vcl-header-login svg { width:18px; height:18px; display:block; }
.vcl-header-login--auth { gap:6px; width:auto; padding:0 10px; }
.vcl-header-login-name { font-size:0.92em; white-space:nowrap; max-width:140px; overflow:hidden; text-overflow:ellipsis; }
.vcl-header--menu-left.vcl-header--has-login:not(.vcl-header--has-btns) .vcl-header-login { margin-left:auto; }
.vcl-header--collapsed .vcl-header-login { position:absolute; right:calc(16px + var(--hdr-page-inset,0px)); top:50%; transform:translateY(-50%); align-self:auto; margin-right:0; width:34px; padding:0 6px; gap:0; }
.vcl-header--collapsed .vcl-header-login-name { display:none; }

.vcl-header-login-panel { position:fixed; z-index:9999; background:var(--tp-surface,#fff); border:1px solid var(--tp-border,#c0c0c0); box-shadow:0 4px 14px rgba(0,0,0,0.18); border-radius:4px; padding:10px; display:flex; flex-direction:column; gap:6px; width:220px; }
.vcl-header-login-panel input { font:13px Tahoma,sans-serif; padding:5px 8px; border:1px solid var(--tp-input-border,#c0c0c0); border-radius:3px; outline:none; color:var(--tp-fg,#222); background:var(--tp-input-bg,#fff); }
.vcl-header-login-panel input:focus { border-color:#5b9dd9; }
.vcl-header-login-panel button { font:13px Tahoma,sans-serif; padding:5px 10px; border:1px solid var(--tp-input-border,#b5b5b5); border-radius:3px; background:var(--tp-btn-bg,#f3f3f3); cursor:pointer; color:var(--tp-fg,#222); }
.vcl-header-login-panel button:hover { background:var(--tp-hover,#e6e6e6); }
.vcl-header-login-err { color:#c0392b; font-size:0.85em; min-height:0; }
/* v404 (tsw2 v334): the sign-in <-> create-account toggle link under the login panel. W built the toggle
   DOM (client.js) in an earlier port but omitted this CSS block (tsw2 has carried it since v326), so W's
   toggle link had been inheriting the body font (too big) -- exactly the defect v334 fixes. Ported verbatim
   from tsw2 v334, landed at the v334 value (font 13px = the Sign in / Create account button, not the pre-v334 11px). */
.vcl-header-login-toggle { text-align: center; margin-top: 2px; }
.vcl-header-login-toggle a { font: 13px Tahoma, sans-serif; color: var(--tp-accent, #2563eb); text-decoration: none; cursor: pointer; }
.vcl-header-login-toggle a:hover { text-decoration: underline; }

/* v403 (tsw2 v333): public @username + avatar. The header shows a small round avatar thumbnail in the account
   button when a user has one. (v404 (tsw2 v334): the signup avatar PICKER was removed -- avatar upload will
   live on the user profile page; the thumbnail display + the "check your email" message stay.) */
.vcl-header-avatar {
  width: 20px; height: 20px; border-radius: 50%; object-fit: cover;
  display: block; flex: 0 0 auto; border: 1px solid var(--tp-border, #c0c0c0);
}
.vcl-header-login-msg {
  font: 13px Tahoma, sans-serif; color: var(--tp-fg, #1f2937);
  background: var(--tp-surface-2, #f0fdf4); border: 1px solid #86efac; border-radius: 4px;
  padding: 10px 12px; text-align: center; line-height: 1.4;
}

/* v405 (tsw2 v335): the "My profile" modal (avatar / display name / @username / change password) */
.vcl-header-modal-overlay {
  position: fixed; inset: 0; z-index: 10000; background: rgba(0, 0, 0, 0.42);
  display: flex; align-items: flex-start; justify-content: center; padding: 8vh 16px 16px;
  font: 13px Tahoma, sans-serif;
}
.vcl-header-modal {
  width: 360px; max-width: 100%; background: var(--tp-surface, #fff); color: var(--tp-fg, #222);
  border: 1px solid var(--tp-border, #c0c0c0); border-radius: 6px; box-shadow: 0 10px 34px rgba(0, 0, 0, 0.28);
  max-height: 84vh; display: flex; flex-direction: column; overflow: hidden;
}
.vcl-header-modal-head {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 12px 14px; border-bottom: 1px solid var(--tp-border, #e5e7eb);
}
.vcl-header-modal-title { font-size: 15px; font-weight: 600; }
.vcl-header-modal-x {
  border: 0; background: transparent; cursor: pointer; font-size: 22px; line-height: 1;
  color: var(--tp-fg-muted, #6b7280); padding: 0 4px;
}
.vcl-header-modal-x:hover { color: var(--tp-fg, #222); }
.vcl-header-modal-body { padding: 14px; display: flex; flex-direction: column; gap: 12px; overflow-y: auto; }
.vcl-header-modal input {
  font: 13px Tahoma, sans-serif; padding: 6px 8px; border: 1px solid var(--tp-input-border, #c0c0c0);
  border-radius: 3px; outline: none; color: var(--tp-fg, #222); background: var(--tp-input-bg, #fff); width: 100%; box-sizing: border-box;
}
.vcl-header-modal input:focus { border-color: #5b9dd9; }
.vcl-header-prof-ro { background: var(--tp-surface-2, #f3f4f6) !important; color: var(--tp-fg-muted, #6b7280) !important; cursor: not-allowed; }
.vcl-header-prof-avatar-row { display: flex; align-items: center; gap: 14px; }
.vcl-header-prof-avatar {
  width: 64px; height: 64px; border-radius: 50%; flex: 0 0 auto;
  background: var(--tp-surface-2, #eef0f2) center/cover no-repeat; border: 1px solid var(--tp-border, #c0c0c0);
}
.vcl-header-prof-avatar.is-empty { border-style: dashed; }
.vcl-header-prof-avatar-btns { display: flex; flex-direction: column; gap: 6px; }
.vcl-header-prof-field { display: flex; flex-direction: column; gap: 4px; }
.vcl-header-prof-label { font-size: 11px; color: var(--tp-fg-muted, #6b7280); }
.vcl-header-prof-btn2 {
  font: 12px Tahoma, sans-serif; padding: 5px 12px; border: 1px solid var(--tp-input-border, #c0c0c0);
  border-radius: 3px; background: var(--tp-btn-bg, #f3f3f3); cursor: pointer; color: var(--tp-fg, #222);
}
.vcl-header-prof-btn2:hover { background: var(--tp-hover, #e6e6e6); }
.vcl-header-prof-btn2--rm { color: #b91c1c; }
.vcl-header-prof-pwtoggle {
  align-self: flex-start; border: 0; background: transparent; cursor: pointer; padding: 0;
  font: 13px Tahoma, sans-serif; color: var(--tp-accent, #2563eb); text-decoration: none;
}
.vcl-header-prof-pwtoggle:hover { text-decoration: underline; }
.vcl-header-prof-pwtoggle.is-open { font-weight: 600; }
.vcl-header-prof-pw { display: flex; flex-direction: column; gap: 8px; }
.vcl-header-prof-msg { font-size: 12px; line-height: 1.4; min-height: 0; }
.vcl-header-prof-msg.is-err { color: #c0392b; }
.vcl-header-prof-msg.is-ok { color: #15803d; }
.vcl-header-prof-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 2px; }
.vcl-header-prof-save {
  font: 13px Tahoma, sans-serif; padding: 6px 14px; border: 1px solid var(--tp-accent, #2563eb); border-radius: 3px;
  background: var(--tp-accent, #2563eb); color: #fff; cursor: pointer;
}
.vcl-header-prof-save:hover { filter: brightness(1.06); }
.vcl-header-prof-save:disabled { opacity: 0.6; cursor: default; }

/* v406 (tsw2 v336): the "My license" modal (reuses the .vcl-header-modal* shell) */
.vcl-header-lic-empty { font-size: 13px; color: var(--tp-fg-muted, #6b7280); }
.vcl-header-lic-cta { align-self: flex-start; font: 13px Tahoma, sans-serif; color: var(--tp-accent, #2563eb); text-decoration: none; }
.vcl-header-lic-cta:hover { text-decoration: underline; }
.vcl-header-lic-card {
  border: 1px solid var(--tp-border, #e5e7eb); border-radius: 8px; padding: 14px;
  display: flex; flex-direction: column; gap: 8px; background: var(--tp-surface-2, #f9fafb);
}
.vcl-header-lic-card + .vcl-header-lic-card { margin-top: 4px; }
.vcl-header-lic-top { display: flex; align-items: center; gap: 8px; }
.vcl-header-lic-badge {
  display: inline-block; font-size: 12px; font-weight: bold; padding: 4px 12px; border-radius: 20px;
  background: #eef6ee; color: #15803d; border: 1px solid #cfe8cf;
}
.vcl-header-lic-status { font-size: 11px; text-transform: uppercase; letter-spacing: .4px; color: var(--tp-fg-muted, #6b7280); }
.vcl-header-lic-status.is-active { color: #15803d; }
.vcl-header-lic-status.is-expired, .vcl-header-lic-status.is-revoked { color: #c0392b; }
.vcl-header-lic-prod { font-size: 13px; font-weight: 600; color: var(--tp-fg, #222); }
.vcl-header-lic-label { font-size: 11px; color: var(--tp-fg-muted, #6b7280); }
.vcl-header-lic-keyrow { display: flex; gap: 8px; align-items: center; }
.vcl-header-lic-key {
  flex: 1; font-family: Consolas, 'Courier New', monospace; font-size: 13px; letter-spacing: .5px;
  background: var(--tp-surface, #fff); border: 1px solid var(--tp-border, #e5e7eb); border-radius: 4px;
  padding: 8px 10px; color: var(--tp-fg, #222); word-break: break-all;
}
.vcl-header-lic-copy {
  font: 12px Tahoma, sans-serif; padding: 8px 12px; border: 1px solid var(--tp-input-border, #c0c0c0);
  border-radius: 4px; background: var(--tp-btn-bg, #f3f3f3); cursor: pointer; color: var(--tp-fg, #222); white-space: nowrap;
}
.vcl-header-lic-copy:hover { background: var(--tp-hover, #e6e6e6); }
.vcl-header-lic-meta { font-size: 12px; color: var(--tp-fg-muted, #6b7280); }

/* v483: the language picker. Cloned from .vcl-header-login so it shares the header's 34px stretch box and
   hover, then given a text badge instead of an svg. */
.vcl-header-lang { display:flex; align-items:center; justify-content:center; box-sizing:border-box; min-width:34px; align-self:stretch; padding:0 8px; background:none; border:none; cursor:pointer; color:inherit; flex:0 0 auto; }
.vcl-header-lang:hover { background:var(--tp-hover,rgba(0,0,0,0.06)); }
.vcl-header-lang-code { font-size:12px; font-weight:600; letter-spacing:.4px; line-height:1; }

/* COLLAPSED STATE -- a deliberate decision, not a clone. Collapsed, the burger is position:absolute left:16px
   and the login pins right: a TWO-ANCHOR layout with no third slot. Dropping a third stretch box in there
   overlaps one of them. So the picker is hidden and its entries are appended to the burger popup instead
   (see langPick + the burger's own renderPopupMenu call). */
.vcl-header--collapsed .vcl-header-lang { display:none; }

/* THTMLMemo */
.vcl-htmlmemo {
  box-sizing: border-box;
  border: 1px solid #7a7a7a;
  background: #fff;
  font: 12px Arial, sans-serif;
  overflow: auto;
  padding: 4px;
  color: #000;
}

/* THTMLText */
.vcl-htmltext {
  box-sizing: border-box;
  font: 12px Arial, sans-serif;
  overflow: auto;
  color: #000;
}
.vcl-htmltext:empty::before {
  content: 'HTML';
  color: #b0b0b0;
  font-style: italic;
}

/* TpAdminButton */
/* TpAdminButton (v372) — the DimWhenLocked appearance: visible but disabled + greyed, so users can
   SEE what a higher level would unlock (the reference's dim+grey mode). Hidden mode reuses
   .tp-access-hidden from TpAuthSetup's stylesheet. */
.tp-admin-dim {
  opacity: 0.45;
  filter: grayscale(60%);
  pointer-events: none;
}

/* TpAuthSetup */
/* TpAuthSetup (v300) — access-gating visibility class. Layered OVER a control's own Visible
   (the gate never touches the worker-side Visible mirror — same stance as the reference). */
.tp-access-hidden { display: none !important; }

/* TPayPal */
/* TPayPal is a NON-VISUAL component: it uses the shared .vcl-nonvisual puck (display:none at runtime,
   revealed at design by ServeDesign's `.vcl-nonvisual{display:block!important}`; the instance name is
   the ::after label). Both rules live in components/Data/TMySQLDatabase/styles.css (loaded via
   /components.css). Here we override only the puck GLYPH with a PayPal-blue badge so it's recognizable
   on the design canvas. The element still exists (hidden) at runtime so method calls can target it. */

.vcl-nonvisual.vcl-paypal {
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Crect x='.5' y='.5' width='23' height='23' rx='4' fill='%23003087'/%3E%3Cpath d='M9 6h5.2c2 0 3.3 1.2 3 3.1-.3 2.2-2 3.3-4.2 3.3H11l-.6 4H8.2L9 6z' fill='%23ffffff'/%3E%3Cpath d='M12.4 9h3.6c2 0 3.3 1.1 3 3-.3 2.2-2 3.3-4.2 3.3h-1.9l-.6 3.7h-2.1l1.2-7.7' fill='%23009cde' opacity='.9'/%3E%3C/svg%3E") center / 24px 24px no-repeat;
}

/* TpBadge */
.vcl-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 11px;
  background: #e8551f;
  color: #fff;
  font: bold 10px Tahoma, sans-serif;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  box-sizing: border-box;
}

/* TpBars */
.vcl-bars {
  background: #fff;
  border: 1px solid #c9c9d4;
  border-radius: 4px;
  box-sizing: border-box;
}

/* TpClock */
.vcl-clock {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: #1a1a2e;
  color: #00e5a0;
  font: bold 14px Consolas, monospace;
  border-radius: 4px;
  letter-spacing: 1px;
  box-sizing: border-box;
}

/* TPDFView */
/* TPDFView — the browser's native PDF viewer in an <iframe>. The src is server-rendered from the URL
   prop, so a configured viewer shows the real PDF even on /design (no JS needed); `credentialless` lets
   a cross-origin/CORS PDF load while the page stays cross-origin-isolated (same as TYouTube). Runtime
   URL change is the SetURL method. #525659 is the native viewer's surface (shows while blank/loading). */

.vcl-pdfview {
  box-sizing: border-box;
  display: block;
  border: 1px solid #c2c7d0;
  background: #525659;
}

/* TpGraph */
/* TpGraph — the host carries the geometry (inline {Style}); client.js sizes + draws the <canvas>.
   On /design (no client.js) the canvas stays empty, so a faint chart-sketch background on the host
   gives a design-time hint. At runtime the canvas paints an opaque chart over it (the first draw op
   fills the background), and — with no app data — the engine synthesises a sample curve + state band. */

.vcl-graph {
  box-sizing: border-box;
  position: relative;
  overflow: hidden;
  background: #ffffff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='90' preserveAspectRatio='none'%3E%3Crect width='160' height='90' fill='%23fafafa'/%3E%3Cg stroke='%23ececec'%3E%3Cline x1='28' y1='8' x2='28' y2='74'/%3E%3Cline x1='28' y1='74' x2='152' y2='74'/%3E%3Cline x1='28' y1='30' x2='152' y2='30'/%3E%3Cline x1='28' y1='52' x2='152' y2='52'/%3E%3C/g%3E%3Cpolyline fill='none' stroke='%23d62728' stroke-width='1.5' points='28,58 50,40 72,48 94,24 116,34 138,18 152,26'/%3E%3Crect x='28' y='78' width='40' height='8' fill='%239e9e9e'/%3E%3Crect x='68' y='78' width='34' height='8' fill='%231f77b4'/%3E%3Crect x='102' y='78' width='50' height='8' fill='%23ff7f0e'/%3E%3C/svg%3E") center / cover no-repeat;
}
.vcl-graph-canvas { display: block; width: 100%; height: 100%; }

/* TpSparkline */
.vcl-spark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: #f7f7fa;
  border: 1px solid #c9c9d4;
  border-radius: 4px;
  box-sizing: border-box;
  overflow: hidden;
}

/* TpToggle */
.vcl-toggle {
  cursor: pointer;
  border: 1px solid #2a7d6f;
  border-radius: 14px;
  background: linear-gradient(to bottom, #3ec8b0, #2a9d8a);
  background-clip: padding-box;
  color: #fff;
  font: 11px Tahoma, sans-serif;
  box-sizing: border-box;
}
.vcl-toggle:active { background: linear-gradient(to bottom, #2a9d8a, #3ec8b0); }

/* .tp-on — set imperatively by the shim's Activate method via the DOM bridge (v038) */
.vcl-toggle.tp-on {
  background: linear-gradient(to bottom, #ffd34d, #f0a818);
  border-color: #c47e00;
  color: #3a2a00;
  box-shadow: 0 0 6px 1px rgba(240, 168, 24, 0.7);
}

/* TQRCode */
/* TQRCode — hand-rolled QR code component. The host carries the geometry (inline {Style});
   client.js renders a crisp SVG that fills the box (width/height 100% + viewBox), so the QR is
   sharp at any size. On /design (no client.js) the static template SVG skeleton is shown. */

.vcl-qrcode {
  box-sizing: border-box;
  display: block;
  overflow: hidden;
  background: transparent;
  line-height: 0;          /* avoid inline-SVG baseline gap */
}
.vcl-qrcode > svg { display: block; width: 100%; height: 100%; }

/* TScrollStory */
/* TScrollStory — the scroll-stopping story section (v313). The comp's root element IS the scroll
   runway (its designed height); .tp-story-sticky pins to the window scrollport while the runway
   passes. Content colours come from the slides themselves — no theme tokens by design. */
.vcl-scrollstory { overflow: visible; }

/* the static design/template placeholder (replaced by client.js) */
.tp-story-design {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 8px;
  background: linear-gradient(160deg, #1b2735 0%, #090a0f 100%);
  color: #fff; text-align: center; overflow: hidden;
}
.tp-story-design-head { font-size: 22px; font-weight: bold; letter-spacing: .5px; }
.tp-story-design-sub  { font-size: 11px; opacity: .65; }
/* v476: the design-time placeholder TEXT moved out of template.html and into CSS-generated content,
   scoped to the design canvas (.tp-design is put on the form host by dfmRendererUnit when DesignMode).
   Before this it was baked into every EXPORTED page: a scroll-story landing page shipped the literals
   "Scroll Story" and "right-click -> Slides... to add slides" to Google, in every language.
   CSS ::before content is not indexed, and the designer still sees exactly what it saw. */
.tp-design .tp-story-design-head::before { content: 'Scroll Story'; }
.tp-design .tp-story-design-sub::before  { content: 'right-click \2192  Slides\2026  to add slides'; }
.tp-story-design-dots span, .tp-story-dots span {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  background: rgba(255,255,255,.45); margin: 0 3px;
}
.tp-story-design-badge {
  position: absolute; top: 6px; right: 8px; font-size: 10px; color: #fff;
  background: rgba(0,0,0,.55); border-radius: 9px; padding: 2px 8px;
}

/* runtime */
.tp-story-sticky {
  position: sticky; top: 0; width: 100%; overflow: hidden; background: inherit;
}
.tp-story-slide { position: absolute; inset: 0; }
.tp-story-bg {
  position: absolute; inset: -1px; background-size: cover; background-repeat: no-repeat;
  will-change: transform, opacity;
}
.tp-story-shade { position: absolute; inset: 0; pointer-events: none; }
.tp-story-content {
  position: absolute; inset: 0; display: flex; flex-direction: column; gap: 12px;
  padding: 6%; box-sizing: border-box;
}
.tp-pos-center       { align-items: center;     justify-content: center; text-align: center; }
.tp-pos-top          { align-items: center;     justify-content: flex-start; text-align: center; }
.tp-pos-bottom       { align-items: center;     justify-content: flex-end; text-align: center; }
.tp-pos-left         { align-items: flex-start; justify-content: center; text-align: left; }
.tp-pos-right        { align-items: flex-end;   justify-content: center; text-align: right; }
.tp-pos-top-left     { align-items: flex-start; justify-content: flex-start; text-align: left; }
.tp-pos-top-right    { align-items: flex-end;   justify-content: flex-start; text-align: right; }
.tp-pos-bottom-left  { align-items: flex-start; justify-content: flex-end; text-align: left; }
.tp-pos-bottom-right { align-items: flex-end;   justify-content: flex-end; text-align: right; }
.tp-story-heading { font-size: clamp(26px, 5vw, 52px); font-weight: bold; line-height: 1.1; margin: 0; text-shadow: 0 2px 12px rgba(0,0,0,.35); }
.tp-story-sub     { font-size: clamp(15px, 2.2vw, 24px); opacity: .92; text-shadow: 0 1px 8px rgba(0,0,0,.35); }
.tp-story-body    { font-size: clamp(13px, 1.5vw, 17px); max-width: 46em; opacity: .88; white-space: pre-line; }
.tp-story-cta {
  font: inherit; font-size: clamp(13px, 1.6vw, 17px); font-weight: bold; cursor: pointer;
  color: inherit; background: rgba(255,255,255,.14); border: 1px solid currentColor;
  border-radius: 24px; padding: 10px 26px; margin-top: 6px; backdrop-filter: blur(2px);
}
.tp-story-cta:hover { background: rgba(255,255,255,.28); }
.tp-story-dots {
  position: absolute; right: 14px; top: 50%; transform: translateY(-50%);
  display: flex; flex-direction: column; gap: 4px; z-index: 5;
}
.tp-story-dots span { cursor: pointer; transition: background .2s, transform .2s; margin: 0; }
.tp-story-dots span.tp-on { background: #fff; transform: scale(1.35); }
.tp-story-hint {
  position: absolute; left: 50%; bottom: 12px; transform: translateX(-50%); z-index: 5;
  width: 22px; height: 22px; border-right: 3px solid rgba(255,255,255,.85);
  border-bottom: 3px solid rgba(255,255,255,.85); rotate: 45deg;
  animation: tpStoryHint 1.6s ease-in-out infinite; pointer-events: none;
}
@keyframes tpStoryHint {
  0%, 100% { transform: translate(-50%, 0); opacity: .85; }
  50%      { transform: translate(-50%, 8px); opacity: .35; }
}

/* TDBCalendar */
/* TDBCalendar — day/month appointment calendar widget styles.
   Ported from the reference IDE (tpwebide/styles/classic.css, the .vcl-cal block).
   Adaptations for this package:
     - .cal-app-car renamed to .cal-app-object (the appointment first line).
     - pat4.gif / pat7.png hatches replaced with a CSS repeating-linear-gradient
       so NO binary assets are needed.
     - wrapper + toolbar styles added at the top.
   All CSS-variable usages (var(--cal-line) etc.) are kept as-is. */

/* ---- wrapper + toolbar (host chrome around the .vcl-cal grid) ---- */
.vcl-dbcalendar-wrap {
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  background: #fff;
  border: 1px solid #7a7a7a;
  overflow: hidden;
  font: 13px Tahoma, "Segoe UI", sans-serif;
}
.vcl-dbcalendar-toolbar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  flex-wrap: wrap;   /* N11: a too-narrow calendar wraps the toolbar instead of clipping its buttons */
  gap: 6px;
  padding: 3px 6px;
  background: linear-gradient(#f7f7f7, #ececec);
  border-bottom: 1px solid #cfcfcf;
  font-size: 12px;
}
.vcl-dbcalendar-toolbar button { font: inherit; padding: 1px 8px; cursor: pointer; flex: 0 0 auto; }   /* N11: keep buttons at size (don't shrink them away) */
/* N11: a long localized title (e.g. "onsdag 30. september 2026") ellipsizes rather than pushing the Day/Month buttons off. */
.vcl-dbcalendar-toolbar .tp-cal-title { font-weight: bold; margin: 0 4px; min-width: 0; flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vcl-dbcalendar-toolbar .tp-cal-spacer { flex: 1 1 auto; }
.vcl-dbcalendar-wrap .vcl-cal { flex: 1 1 auto; min-height: 0; }
/* C25: pre-boot placeholder shown until the client.js renderer runs. BOTH the running app AND the /design canvas
   load this client.js and REPLACE it (innerHTML='') with a real grid — /design draws a STATIC grid from the props
   (no /api/db, per the C17 design gate), the running app draws the live data-bound calendar. (Earlier this comment
   claimed /design didn't load the client.js at all — that stopped being true when the design canvas gained the
   inert static render.) */
.tp-cal-ph {
  width: 100%; height: 100%; box-sizing: border-box;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
  text-align: center; color: #7a8aa0;
  background:
    repeating-linear-gradient(0deg,  #eef2f8 0 1px, transparent 1px 26px),
    repeating-linear-gradient(90deg, #eef2f8 0 1px, transparent 1px 88px);
}
.tp-cal-ph-icon { font-size: 40px; line-height: 1; opacity: .75; }
.tp-cal-ph-title { font-weight: bold; font-size: 15px; color: #4a7; }
.tp-cal-ph-sub { font-size: 11px; color: #9aa6ba; max-width: 80%; }

/* TCalendar — day/month appointment calendar; one box, View toggles which view.
   The whole widget is built by bootstrap's renderCalendar(el) into child layers;
   every rule here is scoped under .vcl-cal so it never leaks to the host page. */
.vcl-cal {
  position: relative;
  overflow: hidden;
  background: #fff;
  box-sizing: border-box;
  font-family: Tahoma, Arial, sans-serif;
  -webkit-user-select: none;
  -moz-user-select: none;
  user-select: none;
}
.vcl-cal .cal-header-layer,
.vcl-cal .cal-grid-layer,
/* touch-action:none (N1): the day view's drag surface must not let a touch pan/scroll the page — the finger
   drives move/resize/create instead. Set on the layer AND the blocks/handle so it holds wherever a drag starts. */
.vcl-cal .cal-apps-layer { position: absolute; inset: 0; touch-action: none; }
/* time-gutter sidebars (CalColors.Sidebar; bg set inline by renderCalendar) */
.vcl-cal .cal-sidebar { position: absolute; pointer-events: none; z-index: 0; }
/* grid line colour = CalColors.Lines (one colour). Solid on the hour, DASHED at the half-hour —
   faithful to the original (the dash is the distinction; .cal-grid-line-hour overrides via later order). */
.vcl-cal .cal-grid-line {
  position: absolute; left: 0; right: 0;
  border-bottom: 1px dashed var(--cal-line, #99BCE8); pointer-events: none;
}
.vcl-cal .cal-grid-line-hour { border-bottom: 1px solid var(--cal-line, #99BCE8); }
.vcl-cal .cal-grid-column {
  position: absolute; top: 0; bottom: 0;
  border-left: 1px solid var(--cal-line, #99BCE8); pointer-events: none;
}
/* Extra/waiting columns: a FAINT translucent type tint over the root CalColors.Background (which shows
   through), so the background applies to ALL positions while the column-type cue is kept. */
.vcl-cal .cal-col-extra   { position: absolute; background: rgba(255, 110, 210, 0.10); z-index: 0; pointer-events: none; }
.vcl-cal .cal-col-waiting { position: absolute; background: rgba(120, 120, 150, 0.10); z-index: 0; pointer-events: none; }
/* TimeLine.ShowTimeButtons corner buttons (AddStart/AddEnd/DelStart/DelEnd). C12: the 8 /img/cal/*.png assets
   were MISSING (broken images). Replaced with self-contained inline-SVG data-URIs — COEP-safe, no binary assets
   (rule K6). A top edge-bar = "start", a bottom edge-bar = "end"; a green "+" = add, a red "−" = delete. Default
   is all-grey; hover colours the +/− sign (green/red), matching the original grayscale-std → colour-hover cue. */
.vcl-cal .cal-timebtn { position: absolute; width: 18px; height: 24px; z-index: 6; cursor: pointer;
  background-size: contain; background-repeat: no-repeat; background-position: center; }
.vcl-cal .cal-tb-addstart       { background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 24'><rect x='3' y='3' width='12' height='2' rx='1' fill='%23888'/><path d='M9 7v8M5 11h8' stroke='%23888' stroke-width='2' stroke-linecap='round'/></svg>"); }
.vcl-cal .cal-tb-addstart:hover { background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 24'><rect x='3' y='3' width='12' height='2' rx='1' fill='%23888'/><path d='M9 7v8M5 11h8' stroke='%232e7d32' stroke-width='2' stroke-linecap='round'/></svg>"); }
.vcl-cal .cal-tb-addend         { background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 24'><rect x='3' y='19' width='12' height='2' rx='1' fill='%23888'/><path d='M9 9v8M5 13h8' stroke='%23888' stroke-width='2' stroke-linecap='round'/></svg>"); }
.vcl-cal .cal-tb-addend:hover   { background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 24'><rect x='3' y='19' width='12' height='2' rx='1' fill='%23888'/><path d='M9 9v8M5 13h8' stroke='%232e7d32' stroke-width='2' stroke-linecap='round'/></svg>"); }
.vcl-cal .cal-tb-delstart       { background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 24'><rect x='3' y='3' width='12' height='2' rx='1' fill='%23888'/><path d='M5 11h8' stroke='%23888' stroke-width='2' stroke-linecap='round'/></svg>"); }
.vcl-cal .cal-tb-delstart:hover { background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 24'><rect x='3' y='3' width='12' height='2' rx='1' fill='%23888'/><path d='M5 11h8' stroke='%23c62828' stroke-width='2' stroke-linecap='round'/></svg>"); }
.vcl-cal .cal-tb-delend         { background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 24'><rect x='3' y='19' width='12' height='2' rx='1' fill='%23888'/><path d='M5 13h8' stroke='%23888' stroke-width='2' stroke-linecap='round'/></svg>"); }
.vcl-cal .cal-tb-delend:hover   { background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 18 24'><rect x='3' y='19' width='12' height='2' rx='1' fill='%23888'/><path d='M5 13h8' stroke='%23c62828' stroke-width='2' stroke-linecap='round'/></svg>"); }
.vcl-cal .cal-header-bg {
  position: absolute; z-index: 9;
  background: var(--cal-hdr-bg, linear-gradient(to bottom, #BFD4EF, #D3E2F4));
  border-bottom: 1px solid #ABC7EC;
}
.vcl-cal .cal-weekno {
  position: absolute; z-index: 11;
  display: flex; align-items: center; justify-content: center;
  color: #cc0000; font-weight: bold; font-size: 12px;
  overflow: hidden; pointer-events: none;
}
.vcl-cal .cal-column-header {
  position: absolute; top: 0;
  border-bottom: 1px solid #ABC7EC;
  border-left: 1px solid var(--cal-line, #99BCE8);
  background: var(--cal-hdr-bg, linear-gradient(to bottom, #BFD4EF, #D3E2F4));
  display: flex; flex-direction: column; justify-content: center; align-items: center;
  font-size: 12px; color: #3C408C; z-index: 10; font-weight: bold;
  box-sizing: border-box; overflow: hidden; padding: 0 4px;
}
.vcl-cal .cal-column-header span { font-weight: normal; font-size: 10px; opacity: 0.8; }
.vcl-cal .cal-time-label {
  position: absolute; left: 2px;
  font-size: 12px; color: #334455; pointer-events: none; font-weight: bold;
}
.vcl-cal .cal-time-label b {
  font-size: 9px; vertical-align: top; text-decoration: underline; margin-left: 1px;
}
.vcl-cal .cal-break-area {
  position: absolute;
  background: repeating-linear-gradient(45deg, #f9f9f9, #f9f9f9 10px, #f2f2f2 10px, #f2f2f2 20px);
  opacity: 0.7; z-index: 1; display: flex; align-items: center; padding-left: 12px;
  color: #ff3333; font-weight: bold; pointer-events: none;
  border-top: 1px solid #ffcccc; border-bottom: 1px solid #ffcccc;
}
/* Out-of-setup band: the expanded slice(s) of the day window OUTSIDE the open day-setup hours (the day view
   grows to show appointments before/after the work hours, or any app on a closed day). Cross-hatch via a CSS
   gradient (was pat7.png), behind the appointments (z-index 1). No opaque base — the root CalColors.Background
   shows through; the cross-hatch plus a faint dim mark the off-schedule slice. */
.vcl-cal .cal-outsetup {
  position: absolute; z-index: 1; pointer-events: none;
  background-color: rgba(0, 0, 0, 0.04);
  background-image: repeating-linear-gradient(45deg, rgba(0,0,0,.06) 0 6px, transparent 6px 12px);
  background-repeat: repeat;
}
.vcl-cal .cal-footer {
  position: absolute; left: 0; right: 0; bottom: 0;
  background-color: var(--cal-ftr-bg, #D3E2F4); border-top: 1px solid #99BCE8; z-index: 10;   /* N13: 0.5px → 1px */
  display: flex; align-items: center; padding: 0 12px;
  font-size: 11px; color: #334455; box-sizing: border-box;
}
.vcl-cal .cal-footer > div { margin-right: 22px; }
.vcl-cal .cal-version { margin-left: auto; margin-right: 4px; font-weight: bold; opacity: 0.5; }
/* Appointment blocks: one .cal-appointment per Appointments.Strings line,
   absolutely positioned in .cal-apps-layer. Type-specific background is set inline by
   drawApps; the default (type 0) colour lives here. */
/* Body/header backgrounds come from per-block CSS vars (drawCalApps sets them per state);
   :hover swaps to the state's Active shade. Header height/font/align are inline (AppHeader props). */
.vcl-cal .cal-appointment {
  position: absolute; box-sizing: border-box; overflow: hidden;
  border: 1px solid #8f8f8f; border-radius: 3px;
  background: var(--cal-app-bg, #DBEFFE); z-index: 5; cursor: pointer;
  touch-action: none;   /* N1: a touch on a block drags/resizes it, never scrolls the page */
}
.vcl-cal .cal-appointment:hover { background: var(--cal-app-bgh, #E6F3FE); }
/* N2: a visible keyboard-focus ring for appointments + day cells (mouse focus stays unadorned via :focus-visible). */
.vcl-cal .cal-appointment:focus-visible { outline: 2px solid #1a73e8; outline-offset: -1px; z-index: 11; }
/* N16: waiting-queue items (pos 0) had the .cal-app-waiting class but NO rule — they looked like normal blocks.
   Give the queue a distinct read: a dashed outline + a purple left accent + a faint accent wash. */
.vcl-cal .cal-appointment.cal-app-waiting {
  border-style: dashed;
  border-left: 3px solid #7e57c2;
  background-image: linear-gradient(90deg, rgba(126, 87, 194, 0.12), transparent 62%);
}
.vcl-cal .cal-app-header {
  font-size: 10px; text-align: center;
  border-bottom: 1px solid #8f8f8f; background: var(--cal-app-hdrbg, #C8E6FF);   /* N13: 0.5px → 1px */
  white-space: nowrap; overflow: hidden;
}
.vcl-cal .cal-app-content {
  padding: 4px;
  font-size: 11px; line-height: 1.2; overflow: hidden;
}
.vcl-cal .cal-app-object { font-weight: bold; margin-bottom: 2px; color: #000; }
.vcl-cal .cal-app-user { color: #444; }
.vcl-cal .cal-app-comment { color: #ff3333; font-style: italic; margin-top: 4px; font-size: 10px; }
/* Blocking placeholder (type 3, the "udefinert" customer): a diagonal hatch (was pat4.gif), tiled,
   marks the position as blocked for that time. Body shows only the comment (no object/customer — drawCalApps
   skips them); the header keeps the time range. Pattern persists on :hover. */
.vcl-cal .cal-appointment.cal-app-blocking,
.vcl-cal .cal-appointment.cal-app-blocking:hover,
.vcl-cal .cal-month-app.cal-app-blocking {
  background-image: repeating-linear-gradient(45deg, rgba(0,0,0,.06) 0 6px, transparent 6px 12px);
  background-repeat: repeat;
}
/* selected/dragged block + the bottom resize grip. */
.vcl-cal .cal-appointment.active {
  border-width: 1.5px; border-color: #000; box-shadow: 0 0 8px rgba(0,0,0,0.4); z-index: 10;
}
.vcl-cal .cal-resize-handle {
  position: absolute; left: 0; right: 0; bottom: 0; height: 8px;
  cursor: ns-resize; background: linear-gradient(transparent, rgba(0,0,0,0.06));
  touch-action: none;   /* N1: touch-resize, don't scroll */
}
/* Drag-to-create guiding rectangle (the pending new appointment, above the blocks). */
.vcl-cal .cal-create-ghost {
  position: absolute; box-sizing: border-box;
  border: 1.5px dashed #3b78e7; background: rgba(59, 120, 231, 0.12);
  border-radius: 3px; z-index: 8; pointer-events: none;
  font-size: 10px; line-height: 1.3; color: #3b78e7; text-align: center; overflow: hidden;
}
/* While a calendar drag is in progress the cursor is forced everywhere. */
body.cal-drag-blocked, body.cal-drag-blocked * { cursor: not-allowed !important; }
body.cal-drag-move,    body.cal-drag-move *    { cursor: move !important; }
body.cal-drag-resize,  body.cal-drag-resize *  { cursor: ns-resize !important; }

/* N16: removed the dead .cal-month-placeholder rule — renderMonth always draws the real grid, the class is never
   emitted (grep-confirmed no client.js reference). */
/* Month view (M1): day-of-week header row, day boxes scaled to each day's own window. */
.vcl-cal .cal-month-dow {
  position: absolute; top: 0; box-sizing: border-box;
  display: flex; align-items: center; justify-content: center;
  background: var(--cal-hdr-bg, linear-gradient(to bottom, #BFD4EF, #D3E2F4));
  border-left: 1px solid var(--cal-line, #99BCE8); border-bottom: 1px solid #ABC7EC;
  font-size: 11px; font-weight: bold; color: #3C408C;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis; padding: 0 2px;   /* N15: a long day name (localized) clips/ellipsizes, never overflows the header cell */
}
.vcl-cal .cal-month-gridbg { position: absolute; pointer-events: none; }    /* bg set inline = Month.GridColor */
.vcl-cal .cal-month-gutterbg { position: absolute; pointer-events: none; }  /* bg set inline = TimeLine.Color */
.vcl-cal .cal-month-hdrband {  /* full-width day-name band — covers the gutter corners (like the day view) */
  position: absolute; background: var(--cal-hdr-bg, linear-gradient(to bottom, #BFD4EF, #D3E2F4));
  border-bottom: 1px solid #ABC7EC; pointer-events: none;
}
.vcl-cal .cal-month-gutterline {  /* week-number gutter row separator */
  position: absolute; height: 0; border-top: 1px solid var(--cal-line, #99BCE8); pointer-events: none;
}
/* THE GRID = a continuous 1px lattice drawn BETWEEN the day rects (Month.GridColor via --cal-month-line). The
   rects are inset, so the lines sit in the margin with a few px each side, and run through the empty slots. */
.vcl-cal .cal-month-gridline.v { position: absolute; pointer-events: none; border-left: 1px solid var(--cal-month-line, var(--cal-line, #99BCE8)); }
.vcl-cal .cal-month-gridline.h { position: absolute; pointer-events: none; border-top:  1px solid var(--cal-month-line, var(--cal-line, #99BCE8)); }
.vcl-cal .cal-month-day {  /* a day RECT — its OWN outline (CalColors.Lines), inset from the grid lines; NOT the grid */
  position: absolute; box-sizing: border-box;
  border: 1px solid var(--cal-line, #99BCE8);
  overflow: hidden; cursor: pointer; background: #fff;
}
.vcl-cal .cal-month-day:hover { background: #f3f8ff; }
.vcl-cal .cal-month-day:focus-visible { outline: 2px solid #1a73e8; outline-offset: -2px; z-index: 6; }   /* N2: keyboard focus ring */
/* N16: removed the dead .cal-month-empty rule (empty lattice slots get no box element — grep-confirmed unused). */
.vcl-cal .cal-month-daynum {  /* top-RIGHT, grey — matches the original month view */
  position: absolute; right: 6px; top: 3px; font-size: 12px; font-weight: bold; color: #777; z-index: 3;
}
.vcl-cal .cal-month-weekno {  /* ISO week number in the left + right gutters (per the original) */
  position: absolute; font-size: 10px; color: #334455; text-align: center; padding-top: 2px; pointer-events: none;
}
.vcl-cal .cal-month-day.cal-month-selected {  /* the calendar's focused day — yellow + red */
  /* N14: keep the border at 1px (was 2px) and add an inset red ring for the bold look — a 2px border shrank
     the content box by 1px vs unselected cells, so selecting jiggled the day's contents. Now zero shift. */
  background: #FFFF77; border-color: #FF0000; box-shadow: inset 0 0 0 1px #FF0000; z-index: 5;
}
/* Month view (M2): in-box content — pos sub-column dividers, break bands, appointment rects.
   (No in-cell horizontal hour lines — the original month view keeps the day cells clean.) */
.vcl-cal .cal-month-poscol {
  position: absolute; width: 0; border-left: 1px solid var(--cal-line, #99BCE8);   /* N13: 0.5px → 1px */
  opacity: 0.4; pointer-events: none;
}
.vcl-cal .cal-month-break {   /* solid grey bar — matches the original (not the day view's hatch) */
  position: absolute; z-index: 1; pointer-events: none; background: #9e9e9e;
}
/* 'extra' column tint inside a month day cell (light pink, like the day view's cal-col-extra); backmost */
.vcl-cal .cal-month-coltint { position: absolute; background: #fff4fd; pointer-events: none; }
.vcl-cal .cal-month-app {
  position: absolute; z-index: 2; box-sizing: border-box;
  border: 1px solid rgba(0, 0, 0, 0.22);   /* N12: a faint outline so two same-colour bars in adjacent slots stay distinct (box-sizing keeps the bar's footprint) */
  pointer-events: none;
}
/* closed day (its day-setup window is blank). Month cell greyed; day view shows a Closed banner. */
.vcl-cal .cal-month-closed {
  background: repeating-linear-gradient(45deg, #f0f0f0, #f0f0f0 6px, #e7e7e7 6px, #e7e7e7 12px);
}
.vcl-cal .cal-closed {
  position: absolute; z-index: 5; display: flex; align-items: center; justify-content: center;
  background: repeating-linear-gradient(45deg, #f4f4f4, #f4f4f4 8px, #ececec 8px, #ececec 16px);
  color: #8a8a8a; font-size: 16px; font-style: italic; pointer-events: none;
}

/* N12: the gradient hatches (blocking apps, closed days, out-of-setup slice, break bands) VANISH under Windows
   High-Contrast (forced-colors strips background-image and overrides background-color) and usually in print
   (backgrounds off by default) — those regions would read as blank. Mark them with a system-colour outline so
   they stay distinguishable in both modes. (forced-color-adjust:auto is the default, so the outline is honoured.) */
@media (forced-colors: active), print {
  .vcl-cal .cal-appointment.cal-app-blocking,
  .vcl-cal .cal-month-app.cal-app-blocking,
  .vcl-cal .cal-month-closed,
  .vcl-cal .cal-closed,
  .vcl-cal .cal-outsetup,
  .vcl-cal .cal-break-area,
  .vcl-cal .cal-month-break {
    outline: 1px dashed GrayText;
    outline-offset: -1px;
  }
}

/* TDBCheckBox */
/* v055: TDBCheckBox — checked when the bound field value matches valueChecked (the {DataFieldChecked} token; the
   live feed sets .checked). Display-only (pointer-events:none) — the runtime write-back (Post) is a later step. */
.vcl-dbcheckbox {
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font: 13px Tahoma, "Segoe UI", sans-serif;
  color: #000;
  user-select: none;
}
.vcl-dbcheckbox-input {
  pointer-events: none;   /* display-only */
  margin: 0;
  flex: 0 0 auto;
}
.vcl-dbcheckbox-cap {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* TDBComboBox */
/* v056: TDBComboBox — a dropdown of its `items`; the option equal to the bound field value is selected (the
   {DataFieldOptions} token; the live feed sets select.value). Display-only (pointer-events:none) — the runtime
   write-back (Post on change) is a later step. */
.vcl-dbcombobox {
  box-sizing: border-box;
  display: inline-flex;
  align-items: stretch;
  font: 13px Tahoma, "Segoe UI", sans-serif;   /* FALLBACK — the {Style} FontCss overrides when the model sets font */
  color: #000;
}
.vcl-dbcombobox-select {
  flex: 1 1 auto;
  min-width: 0;
  box-sizing: border-box;
  border: 1px solid #7a7a7a;
  background: #fff;
  font: inherit;
  color: inherit;
  padding: 1px 3px;
  pointer-events: none;   /* display-only */
}

/* TDBDateEdit */
/* v079: TDBDateEdit — a data-aware date/time edit (the native-date-input sibling of TDBEdit). `kind` picks the
   input type: date -> <input type=date>, time -> <input type=time>, datetime-local -> <input type=datetime-local>.
   The value is rendered EMPTY at /design and hydrated at runtime by the shared feed (which ships date/time fields
   as ISO yyyy-mm-ddThh:nn:ss; the client slices the part this input needs — see TMySQLQuery/client.js). Display-only
   in browse mode (readonly attr); edit mode unlocks it and the picked value is written back on Post (PostRow parses
   the ISO value into the date column, locale-independent). Modeled on TDBEdit. */
.vcl-dbdateedit {
  box-sizing: border-box;
  display: inline-flex;
  align-items: stretch;
  background: #fff;
  border: 1px solid #7a7a7a;
  overflow: hidden;
  font: 13px Tahoma, "Segoe UI", sans-serif;   /* FALLBACK — the inline {Style} FontCss overrides when the model sets font */
  color: #000;
}
.vcl-dbdateedit-input {
  flex: 1 1 auto;
  min-width: 0;
  border: none;
  outline: none;
  background: transparent;
  font: inherit;     /* inherit the wrapper's font (model fontFamily/fontSize/bold/...) */
  color: inherit;    /* and the model text colour */
  padding: 1px 4px;
}

/* TDBEdit */
/* v049: TDBEdit — a data-aware edit box. On /design its value is the LIVE bound field value (the renderer's
   {DataFieldValue} token, resolved through designDbUnit), or a muted [fieldName] placeholder when the query
   isn't open. The inner input is readonly here (design-time display); the runtime data feed lands in a later
   version. Geometry/surface come from the {Style} chain; this gives the default edit look. */
.vcl-dbedit {
  box-sizing: border-box;
  display: inline-flex;
  align-items: stretch;
  background: #fff;
  border: 1px solid #7a7a7a;
  overflow: hidden;
  font: 13px Tahoma, "Segoe UI", sans-serif;   /* FALLBACK — the inline {Style} FontCss overrides it when the model sets font */
  color: #000;
}
.vcl-dbedit-input {
  flex: 1 1 auto;
  min-width: 0;
  border: none;
  outline: none;
  background: transparent;
  font: inherit;     /* inherit the wrapper's font (model fontFamily/fontSize/bold/...) */
  color: inherit;    /* and the model text colour */
  padding: 1px 4px;
}
/* the [field] placeholder (no live data yet) reads as muted italic, so it's clearly not real data. This matches
   the `value` ATTRIBUTE; refreshDbControls (v433/tsw2 v363) syncs that attribute when it binds a real value, so live
   rows stop matching this selector and render with the model's own font/colour. */
.vcl-dbedit-input[value^="["] { color: #999; font-style: italic; }

/* TDBForum */
/* TDBForum — a simple community forum (v381). A DB-aware control like TDBCalendar: it binds to two
   TMySQLQuery components (topicsQuery/postsQuery) and renders a sections rail + topic list + thread +
   composer. All colours/font come from props, applied by client.js as --tpf-* custom properties on the
   root element (so both the light template default and the prop-driven runtime share one stylesheet).
   v381 (shell): chrome + design mock; live data lands in v2. */
.vcl-forum {
  --tpf-bg: #ffffff; --tpf-header: #3b4a6b; --tpf-accent: #2d6cdf;
  --tpf-text: #1f2430; --tpf-border: #e2e6ee; --tpf-size: 14px;
  overflow: hidden; box-sizing: border-box; display: flex; flex-direction: column;
  background: var(--tpf-bg); color: var(--tpf-text); border: 1px solid var(--tpf-border);
  border-radius: 10px; font-size: var(--tpf-size); line-height: 1.4;
}
.vcl-forum * { box-sizing: border-box; }

/* the static SSR placeholder (replaced by client.js) */
.tp-forum-ph {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 6px;
  background: linear-gradient(160deg, #3b4a6b 0%, #232c42 100%); color: #fff; text-align: center;
}
.tp-forum-ph-head { font-size: 22px; font-weight: 700; }
.tp-forum-ph-sub  { font-size: 11px; opacity: .7; }
/* v476: design-time placeholder text moved out of template.html (it used to ship into every exported
   page) into CSS-generated content scoped to the design canvas. See TScrollStory/styles.css. */
.tp-design .tp-forum-ph-head::before { content: 'Forum'; }
.tp-design .tp-forum-ph-sub::before  { content: 'community forum \2014  renders live in the running app'; }

/* header bar */
.tp-forum-head {
  flex: 0 0 auto; display: flex; align-items: center; gap: 10px;
  padding: 10px 14px; background: var(--tpf-header); color: #fff;
}
.tp-forum-title { font-weight: 700; font-size: 1.15em; }
.tp-forum-spacer { flex: 1 1 auto; }
.tp-forum-btn {
  font: inherit; font-weight: 600; cursor: pointer; color: #fff;
  background: var(--tpf-accent); border: 0; border-radius: 6px; padding: 6px 14px;
}
.tp-forum-btn:hover { filter: brightness(1.08); }
.tp-forum-btn[disabled] { opacity: .5; cursor: default; }

/* body: sections rail + main pane */
.tp-forum-body { flex: 1 1 auto; display: flex; min-height: 0; }
.tp-forum-rail {
  flex: 0 0 180px; border-right: 1px solid var(--tpf-border);
  padding: 8px; overflow: auto; display: flex; flex-direction: column; gap: 2px;
}
.tp-forum-rail-h {
  font-size: .78em; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  opacity: .55; padding: 4px 8px 6px;
}
.tp-forum-sec {
  text-align: left; font: inherit; cursor: pointer; color: var(--tpf-text);
  background: transparent; border: 0; border-radius: 6px; padding: 7px 10px; width: 100%;
}
.tp-forum-sec:hover { background: color-mix(in srgb, var(--tpf-accent) 12%, transparent); }
.tp-forum-sec.tp-on { background: color-mix(in srgb, var(--tpf-accent) 18%, transparent); font-weight: 600; }

.tp-forum-main { flex: 1 1 auto; overflow: auto; padding: 12px 14px; min-width: 0; }

/* topic list */
.tp-forum-list { display: flex; flex-direction: column; gap: 8px; }
.tp-forum-topic {
  display: flex; align-items: center; gap: 10px; cursor: pointer;
  border: 1px solid var(--tpf-border); border-radius: 8px; padding: 10px 12px;
}
.tp-forum-topic:hover { border-color: var(--tpf-accent); }
.tp-forum-topic-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.tp-forum-topic-title { font-weight: 600; min-width: 0; }
/* v391: explicit "Started by <author>" line under the topic title */
.tp-forum-topic-by { font-size: .8em; opacity: .6; }
.tp-forum-topic-author { font-weight: 700; opacity: .95; }
.tp-forum-topic-meta { font-size: .82em; opacity: .6; white-space: nowrap; }

/* v390/v392: admin moderation controls (pin + delete) — on a topic row and in a post head */
.tp-forum-topic-actions { display: inline-flex; align-items: center; gap: 8px; white-space: nowrap; flex: 0 0 auto; }
.tp-forum-pin {
  font: inherit; font-size: .82em; cursor: pointer; color: var(--tpf-accent);
  background: transparent; border: 1px solid var(--tpf-border); border-radius: 6px; padding: 2px 8px;
}
.tp-forum-pin:hover { border-color: var(--tpf-accent); }
.tp-forum-pin.tp-on { background: color-mix(in srgb, var(--tpf-accent) 14%, transparent); font-weight: 600; }
.tp-forum-pin-badge { color: var(--tpf-accent); }
.tp-forum-del { display: inline-flex; align-items: center; gap: 4px; }
.tp-forum-del-btn {
  font: inherit; font-size: .82em; cursor: pointer; color: #c0392b;
  background: transparent; border: 1px solid var(--tpf-border); border-radius: 6px; padding: 2px 8px;
}
.tp-forum-del-btn:hover { border-color: #c0392b; background: color-mix(in srgb, #c0392b 8%, transparent); }
.tp-forum-del-q { font-size: .82em; color: #c0392b; font-weight: 600; }
.tp-forum-del-yes, .tp-forum-del-no {
  font: inherit; font-size: .82em; cursor: pointer; color: var(--tpf-text);
  background: transparent; border: 1px solid var(--tpf-border); border-radius: 6px; padding: 2px 8px;
}
.tp-forum-del-yes { color: #fff; background: #c0392b; border-color: #c0392b; }
.tp-forum-del-yes[disabled], .tp-forum-del-no[disabled] { opacity: .5; cursor: default; }

/* thread view */
.tp-forum-thread { display: flex; flex-direction: column; gap: 10px; }
.tp-forum-back {
  align-self: flex-start; font: inherit; cursor: pointer; color: var(--tpf-accent);
  background: transparent; border: 0; padding: 2px 0; font-weight: 600;
}
.tp-forum-thread-title { font-size: 1.3em; font-weight: 700; }
.tp-forum-post {
  border: 1px solid var(--tpf-border); border-radius: 8px; padding: 10px 12px;
}
.tp-forum-post-head { font-size: .82em; opacity: .65; margin-bottom: 4px; }
.tp-forum-post-author { font-weight: 700; opacity: .95; }
.tp-forum-post-body { white-space: pre-wrap; word-break: break-word; }
.tp-forum-post-edit {
  font: inherit; cursor: pointer; background: transparent; border: 0; padding: 0;
  color: var(--tpf-accent); font-weight: 600;
}
.tp-forum-post-edit:hover { text-decoration: underline; }
.tp-forum-post-editor { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; }
.tp-forum-post-editor .tp-forum-actions { display: flex; justify-content: flex-end; gap: 8px; }

/* composer + empty state */
.tp-forum-composer {
  flex: 0 0 auto; border-top: 1px solid var(--tpf-border); padding: 10px 14px;
  display: flex; gap: 8px; align-items: flex-end;
}
.tp-forum-input, .tp-forum-area {
  font: inherit; color: var(--tpf-text); background: var(--tpf-bg);
  border: 1px solid var(--tpf-border); border-radius: 6px; padding: 8px 10px; width: 100%;
}
.tp-forum-area { resize: vertical; min-height: 40px; }
.tp-forum-empty { opacity: .55; text-align: center; padding: 28px 12px; font-style: italic; }
.tp-forum-note {
  margin-top: 10px; font-size: .8em; opacity: .5; text-align: center;
}

/* v383 writes: new-topic composer + reply box */
.tp-forum-compose { display: flex; flex-direction: column; gap: 8px; max-width: 640px; }
.tp-forum-compose-h { font-size: 1.15em; font-weight: 700; margin-bottom: 2px; }
.tp-forum-compose-actions { display: flex; gap: 8px; }
.tp-forum-btn-ghost { background: transparent; color: var(--tpf-accent); border: 1px solid var(--tpf-border); }
.tp-forum-btn-ghost:hover { filter: none; background: color-mix(in srgb, var(--tpf-accent) 10%, transparent); }
.tp-forum-replybox {
  margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--tpf-border);
  display: flex; flex-direction: column; gap: 8px;
}
.tp-forum-replybox .tp-forum-actions { display: flex; justify-content: flex-end; }
.tp-forum-signin { margin-top: 12px; padding: 10px; text-align: center; opacity: .6; font-size: .9em;
  border-top: 1px solid var(--tpf-border); }
.tp-forum-err { color: #c0392b; font-size: .85em; }

/* v385 attachments: the composer/reply "📎 Attach" bar + pending-file chips */
.tp-forum-attachbar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.tp-forum-attach-btn { padding: 5px 12px; font-size: .9em; }
.tp-forum-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.tp-forum-chip {
  display: inline-flex; align-items: center; gap: 6px; font-size: .82em;
  background: color-mix(in srgb, var(--tpf-accent) 10%, transparent);
  border: 1px solid var(--tpf-border); border-radius: 999px; padding: 3px 6px 3px 10px;
}
.tp-forum-chip-x {
  font: inherit; line-height: 1; cursor: pointer; color: inherit; opacity: .6;
  background: transparent; border: 0; padding: 0 2px; font-size: 1.1em;
}
.tp-forum-chip-x:hover { opacity: 1; color: #c0392b; }

/* v385 attachments: rendered under a post in the thread */
.tp-forum-atts { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.tp-forum-att-imglink { display: inline-block; line-height: 0; border: 1px solid var(--tpf-border); border-radius: 8px; overflow: hidden; }
.tp-forum-att-img { display: block; max-width: 220px; max-height: 220px; width: auto; height: auto; object-fit: contain; background: color-mix(in srgb, var(--tpf-text) 5%, transparent); }
.tp-forum-att-chip {
  display: inline-flex; align-items: center; gap: 6px; font: inherit; font-size: .85em; cursor: pointer;
  color: var(--tpf-text); background: transparent; border: 1px solid var(--tpf-border); border-radius: 8px; padding: 6px 12px;
}
.tp-forum-att-chip:hover { border-color: var(--tpf-accent); }
.tp-forum-att-chip[disabled] { opacity: .5; cursor: default; }
.tp-forum-att-ico { opacity: .7; }
.tp-forum-att-name { font-weight: 600; }
.tp-forum-att-size { opacity: .55; font-size: .9em; }

/* TDBGrid */
/* TDBGrid — hand-rolled data grid (Stage 1: read-only). Look matches the other TDB* controls
   (Tahoma 13, #7a7a7a frame, #0a64c0 selection). The host geometry comes from the inline {Style};
   layout/structure comes from here. client.js rebuilds the body at runtime (virtualized); on /design
   (no client.js) the static template skeleton below is what you see. */

/* v099: UX overlays — a busy spinner (top-right, during paging/detail fetches) and a centred empty state */
.vcl-dbgrid-spinner {
  position: absolute; top: 5px; right: 7px; z-index: 8;
  width: 15px; height: 15px; box-sizing: border-box;
  border: 2px solid #c4d2e6; border-top-color: #0a64c0; border-radius: 50%;
  animation: vcl-dbgrid-spin 0.7s linear infinite;
}
@keyframes vcl-dbgrid-spin { to { transform: rotate(360deg); } }
.vcl-dbgrid-empty {
  position: absolute; left: 0; right: 0; top: 55%; transform: translateY(-50%);
  text-align: center; color: var(--tp-fg-muted, #8a93a0); font-style: italic; pointer-events: none; z-index: 4;
}

.vcl-dbgrid {
  position: relative;            /* v087: positioning context for the frozen-column overlay */
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--tp-surface, #ffffff);   /* v305: theme tokens, fallbacks = pre-v305 literals */
  border: 1px solid var(--tp-border, #7a7a7a);
  font: 13px Tahoma, "Segoe UI", sans-serif;
  color: var(--tp-fg, #000000);
  user-select: none;
}
.vcl-dbgrid:focus { outline: none; }

/* v087: frozen (pinned) left columns — an opaque overlay with a right shadow; its canvas is vertically synced */
.vcl-dbgrid-frozen-head {
  background: var(--tp-surface-2, #f0f0f0);
  border-bottom: 1px solid var(--tp-border, #aaaaaa);
  box-shadow: 2px 0 4px rgba(0, 0, 0, 0.14);
  overflow: hidden;
  white-space: nowrap;
}
.vcl-dbgrid-frozen-body {
  background: var(--tp-surface, #ffffff);
  box-shadow: 2px 0 4px rgba(0, 0, 0, 0.14);
}
.vcl-dbgrid-frozen-canvas { position: relative; will-change: transform; }

/* header ------------------------------------------------------------------ */
.vcl-dbgrid-head {
  flex: 0 0 auto;
  overflow: hidden;
  background: var(--tp-surface-2, #f0f0f0);
  border-bottom: 1px solid var(--tp-border, #aaaaaa);
}
.vcl-dbgrid-head-inner { position: relative; white-space: nowrap; will-change: transform; }
.vcl-dbgrid-hcell {
  position: relative;            /* v086: anchor the resize grip */
  display: inline-block;
  box-sizing: border-box;
  height: 22px;
  line-height: 22px;
  padding: 0 6px;
  font-weight: bold;
  vertical-align: top;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
/* v086: sortable header + sort arrow + drag-to-resize grip */
.vcl-dbgrid-hsort { cursor: pointer; }
.vcl-dbgrid-hsort:hover { background: var(--tp-hover, #e8eef7); }
.vcl-dbgrid-sort { font-size: 9px; color: var(--tp-accent, #0a64c0); }
.vcl-dbgrid-resize { position: absolute; top: 0; right: 0; width: 7px; height: 100%; cursor: col-resize; }
/* v093: drag-to-reorder — header text is the drag handle; the drop target shows a blue left edge */
.vcl-dbgrid-htext { cursor: grab; }
.vcl-dbgrid-drop { box-shadow: inset 3px 0 0 var(--tp-accent, #0a64c0); }

/* body (scroll viewport + absolutely-positioned virtualized rows) --------- */
/* overscroll-behavior: contain -> when the grid's own scroll reaches its top/bottom, the wheel does NOT chain out
   to the page behind it (e.g. the page scrolling under an open modal). Keeps a wheel gesture over the grid inside
   the grid. (v462 / tsw2 v393) */
.vcl-dbgrid-viewport { flex: 1 1 auto; overflow: auto; overscroll-behavior: contain; position: relative; }
.vcl-dbgrid-canvas   { position: relative; }
.vcl-dbgrid-row      { position: absolute; left: 0; white-space: nowrap; }
.vcl-dbgrid-row-alt  { background: var(--tp-grid-row-alt, #f7f9fc); }
.vcl-dbgrid-row-multisel { background: var(--tp-accent-soft, #d8e8fb); }                                     /* v092: multi-selected row */
.vcl-dbgrid-row-sel  { background: var(--tp-accent, #0a64c0); color: var(--tp-accent-fg, #ffffff); }
.vcl-dbgrid-row-sel.vcl-dbgrid-row-multisel { background: var(--tp-accent, #0a64c0); color: var(--tp-accent-fg, #ffffff); }  /* current row wins over multi-sel */
/* v092: indicator / select gutter cell */
.vcl-dbgrid-indcell { color: var(--tp-accent, #0a64c0); font-weight: bold; padding: 0 !important; overflow: hidden; }
.vcl-dbgrid-indcell input[type="checkbox"] { margin: 0; vertical-align: middle; }
/* v098: master-detail — expand chevron + indented detail rows */
.vcl-dbgrid-expcell { padding: 0 !important; }
.vcl-dbgrid-expand { cursor: pointer; color: var(--tp-accent, #0a64c0); font-weight: bold; }
.vcl-dbgrid-detail {
  position: absolute; left: 0; box-sizing: border-box;
  padding-left: 30px; background: var(--tp-tint, #f4f7fb); border-bottom: 1px solid var(--tp-grid-line, #e2e8f1);
  white-space: nowrap; overflow: hidden; color: var(--tp-fg, #2a2a2a);
}
.vcl-dbgrid-detail-head { background: var(--tp-tint, #e7eef7); font-weight: bold; }
/* v100: tree — per-level indent + expand chevron in the tree column */
.vcl-dbgrid-tree-indent { display: inline-block; height: 1px; vertical-align: middle; }
.vcl-dbgrid-treechev { display: inline-block; width: 14px; text-align: center; cursor: pointer; color: var(--tp-accent, #0a64c0); font-weight: bold; }
.vcl-dbgrid-tree-spacer { display: inline-block; width: 14px; }
.vcl-dbgrid-dcell { display: inline-block; min-width: 84px; padding: 0 8px; overflow: hidden; }
.vcl-dbgrid-dhcell { color: var(--tp-fg, #2f4a63); }
.vcl-dbgrid-dmsg { color: var(--tp-fg-muted, #6b7785); font-style: italic; }
.vcl-dbgrid-cell {
  display: inline-block;
  box-sizing: border-box;
  height: 100%;
  vertical-align: top;
  padding: 0 6px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* v096: cell renderers — 'bar' (proportional fill + value text) and 'badge' (coloured pill) */
.vcl-dbgrid-bar { position: relative; height: 14px; margin-top: 3px; background: #e9edf2; border-radius: 3px; overflow: hidden; }
.vcl-dbgrid-bar-fill { position: absolute; left: 0; top: 0; height: 100%; background: #4a90d9; }
/* v244: two identically-positioned text layers (absolute + flex-center so they overlay pixel-for-pixel). Base = dark
   (over the light track); -over = white, clipped to the fill width (over the blue fill). Auto-contrast, split mid-glyph. */
.vcl-dbgrid-bar-text { position: absolute; left: 0; top: 0; right: 0; bottom: 0; display: flex; align-items: center; z-index: 1; font-size: 11px; line-height: 1; padding: 0 4px; color: #14213a; white-space: nowrap; overflow: hidden; }
.vcl-dbgrid-bar-text-over { z-index: 2; color: #fff; }
.vcl-dbgrid-badge { display: inline-block; padding: 0 7px; border-radius: 9px; color: #ffffff; font-size: 11px; font-weight: bold; line-height: 16px; }

/* optional grid lines (toggled by client.js / set in the design template) - */
.vcl-dbgrid-collines .vcl-dbgrid-hcell { border-right: 1px solid var(--tp-grid-line, #cccccc); }
.vcl-dbgrid-collines .vcl-dbgrid-cell  { border-right: 1px solid var(--tp-grid-line, #e2e2e2); }
.vcl-dbgrid-rowlines .vcl-dbgrid-row   { border-bottom: 1px solid var(--tp-grid-line, #ececec); }

/* design-time skeleton: client.js does not run on /design, so the template's rows are laid out
   statically (no absolute positioning / virtualization). */
.vcl-dbgrid-design .vcl-dbgrid-row  { position: static; height: 22px; line-height: 22px; }
.vcl-dbgrid-design .vcl-dbgrid-cell { line-height: 22px; }

/* v083: in-cell editor — an absolutely-positioned input over the cell being edited */
.vcl-dbgrid-editor {
  font: inherit;
  border: 1px solid var(--tp-accent, #0a64c0);
  outline: none;
  padding: 0 5px;
  background: var(--tp-input-bg, #ffffff);
  color: var(--tp-fg, #000000);
  z-index: 5;
}
/* v084: per-type editors — select (combo/lookup) trims side padding so the dropdown arrow fits; the
   checkbox editor centres its small box in the cell rather than left-aligning it. */
.vcl-dbgrid-editor-select { padding: 0 2px; }
.vcl-dbgrid-editor-check  { display: flex; align-items: center; justify-content: center; padding: 0; }

/* the read-only checkbox shown in a checkbox column's cell (display, not the editor) */
.vcl-dbgrid-cell > input[type="checkbox"] { margin: 0; vertical-align: middle; pointer-events: none; }

/* v085: row Insert/Delete footer toolbar (only built when the grid is editable) */
.vcl-dbgrid-foot {
  flex: 0 0 auto;
  display: flex;
  gap: 2px;
  padding: 1px 2px;
  background: var(--tp-surface-2, #f0f0f0);
  border-top: 1px solid var(--tp-border, #aaaaaa);
}
.vcl-dbgrid-foot-btn {
  width: 20px;
  height: 18px;
  line-height: 16px;
  padding: 0;
  font: bold 14px Tahoma, sans-serif;
  cursor: pointer;
  border: 1px solid var(--tp-input-border, #9aa0a6);
  border-radius: 2px;
  background: var(--tp-btn-bg, #ffffff);
  color: var(--tp-btn-fg, #333333);
}
.vcl-dbgrid-foot-btn:hover { background: var(--tp-hover, #e8f0fe); border-color: var(--tp-accent, #0a64c0); }
.vcl-dbgrid-foot-btn:active { background: var(--tp-accent-soft, #d6e4fb); }
/* the phantom new row being entered */
.vcl-dbgrid-row-new .vcl-dbgrid-cell:first-child { box-shadow: inset 2px 0 0 #1f9d4d; }

/* v089: per-column filter row (under the header, horizontally synced) */
.vcl-dbgrid-filter { flex: 0 0 auto; height: 22px; overflow: hidden; background: var(--tp-surface, #fafbfc); border-bottom: 1px solid var(--tp-grid-line, #cccccc); }
.vcl-dbgrid-filter-inner { position: relative; height: 100%; white-space: nowrap; will-change: transform; }
.vcl-dbgrid-filter-cell { display: inline-block; box-sizing: border-box; height: 22px; padding: 1px 2px; vertical-align: top; }
.vcl-dbgrid-filter-input {
  width: 100%; height: 18px; box-sizing: border-box;
  border: 1px solid var(--tp-input-border, #c4c9d0); border-radius: 2px;
  font: 12px Tahoma, sans-serif; padding: 0 3px; color: var(--tp-fg, #000000);
}
.vcl-dbgrid-filter-input:focus { outline: none; border-color: var(--tp-accent, #0a64c0); }

/* v090: collapsible group-header row */
.vcl-dbgrid-grouphdr {
  position: absolute; left: 0; box-sizing: border-box;
  background: var(--tp-tint, #dde6f2); border-bottom: 1px solid var(--tp-grid-line, #b8c4d6);
  font-weight: bold; color: var(--tp-fg, #1a3a5c); padding: 0 6px;
  cursor: pointer; overflow: hidden; white-space: nowrap;
}
.vcl-dbgrid-group-arrow { display: inline-block; width: 12px; color: var(--tp-accent, #0a64c0); }
.vcl-dbgrid-group-count { color: var(--tp-fg-muted, #5a6b80); font-weight: normal; }

/* v088: footer aggregates strip (horizontally synced like the header) */
.vcl-dbgrid-agg { flex: 0 0 auto; height: 20px; overflow: hidden; background: var(--tp-tint, #eef1f6); border-top: 1px solid var(--tp-border, #aaaaaa); }
.vcl-dbgrid-agg-inner { position: relative; height: 100%; white-space: nowrap; will-change: transform; }
.vcl-dbgrid-agg-cell {
  display: inline-block; box-sizing: border-box;
  height: 20px; line-height: 20px; padding: 0 6px;
  font-weight: bold; font-size: 12px; color: var(--tp-fg, #2a2a2a);
  overflow: hidden; white-space: nowrap; vertical-align: top;
}

/* TDBHTMLText */
/* v080: TDBHTMLText — a READ-ONLY block that renders the bound field's value as HTML (innerHTML), the data-aware
   sibling of TDBText (which renders the field as plain text). The field is expected to hold HTML markup (e.g. a
   stored article body); it's rendered, not escaped. On /design the HTML is server-rendered ({DataFieldHtml} — the
   raw field value); in the running app the live feed sets the body's innerHTML. Scrolls when the content overflows.
   Inserted <script> never executes (browsers don't run scripts set via innerHTML). Geometry/surface come from the
   {Style} chain. */
.vcl-dbhtmltext {
  box-sizing: border-box;
  background: #fff;
  border: 1px solid #7a7a7a;
  overflow: auto;
  font: 13px Tahoma, "Segoe UI", sans-serif;   /* FALLBACK — the {Style} FontCss overrides when the model sets font */
  color: #000;
}
.vcl-dbhtmltext-body {
  padding: 3px 6px;
  font: inherit;     /* inherit the wrapper's font (model fontFamily/fontSize/bold/...) */
  color: inherit;    /* and the model text colour */
}
/* keep common block elements from blowing out the box margins */
.vcl-dbhtmltext-body > :first-child { margin-top: 0; }
.vcl-dbhtmltext-body > :last-child { margin-bottom: 0; }
.vcl-dbhtmltext-body img { max-width: 100%; }

/* TDBImage */
/* v059: TDBImage — a data-aware image. The bound dataField holds an image URL (or a data: URI); the SSR sets
   <img src> to the FIRST row's value ({DataFieldImageSrc}), and the live feed (TMySQLQuery/client.js) re-points it
   as the cursor moves. When there's no value the <img> is hidden (empty src) and the dashed picture placeholder
   below shows through — so a freshly-bound TDBImage reads as "an image goes here" on /design. */
.vcl-dbimage {
  box-sizing: border-box;
  position: relative;
  overflow: hidden;
  border: 1px solid #c4c9d0;
  background: #f4f5f7
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48'%3E%3Crect x='4' y='8' width='40' height='32' rx='3' fill='none' stroke='%23a0a6b0' stroke-width='2'/%3E%3Ccircle cx='16' cy='19' r='4' fill='%23a0a6b0'/%3E%3Cpath d='M10 39 L21 25 L29 33 L35 27 L42 35 L42 39 Z' fill='%23c4c9d0'/%3E%3C/svg%3E")
    center / 40px no-repeat;
}
.vcl-dbimage-img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;   /* overridden inline by the {{fit}} token */
}
/* no bound value yet -> hide the <img> so the placeholder behind shows */
.vcl-dbimage-img[src=""],
.vcl-dbimage-img:not([src]) { opacity: 0; }

/* TDBListBox */
/* v053: TDBListBox — a data-aware list of the bound field across ALL rows of its dataset (the web idiom: show
   the data, not a fixed Items list). The current/selected row is highlighted; clicking an item navigates the
   shared cursor (see TDBListBox/client.js) so the navigator + other bound controls follow. On /design the list is
   server-rendered ({DataFieldList}); in the running app the live feed re-renders it. */
.vcl-dblistbox {
  box-sizing: border-box;
  background: #fff;
  border: 1px solid #7a7a7a;
  overflow: hidden;
  font: 13px Tahoma, "Segoe UI", sans-serif;
}
.vcl-dblistbox-items {
  height: 100%;
  overflow-y: auto;
}
.vcl-dblistbox-item {
  padding: 1px 5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
  color: inherit;     /* inherit the model text colour (font-family/size are inherited by the divs automatically) */
}
.vcl-dblistbox-item:hover { background: #eaf2fb; }
.vcl-dblistbox-item-sel,
.vcl-dblistbox-item-sel:hover { background: #0a64c0; color: #fff; }
/* empty / unbound (no rows): a faint hint so the box doesn't read as broken */
.vcl-dblistbox-items:empty::before {
  content: "(no data)";
  display: block;
  padding: 2px 5px;
  color: #aaa;
  font-style: italic;
}

/* TDBLookupComboBox */
/* v077: TDBLookupComboBox — a data-aware lookup dropdown. Like TDBComboBox, but its <option>s come from a SECOND
   (lookup) dataset (listSource): each option's value is the lookup's keyField and its text is the listField. The
   option whose value matches the MAIN dataset's bound field (dataField) is selected. Display-only in browse mode
   (pointer-events:none); in edit mode the shared feed flips pointer-events on so the dropdown is usable, and the
   chosen key is written to the main field on Post (see TMySQLQuery/client.js boundEditControls + dbPost). On
   /design the options are server-rendered ({DataLookupOptions}); in the running app the live feed re-renders them. */
.vcl-dblookupcombobox {
  box-sizing: border-box;
  display: inline-flex;
  align-items: stretch;
  font: 13px Tahoma, "Segoe UI", sans-serif;   /* FALLBACK — the {Style} FontCss overrides when the model sets font */
  color: #000;
}
.vcl-dblookupcombobox-select {
  flex: 1 1 auto;
  min-width: 0;
  box-sizing: border-box;
  border: 1px solid #7a7a7a;
  background: #fff;
  font: inherit;
  color: inherit;
  padding: 1px 3px;
  pointer-events: none;   /* display-only in browse mode; edit mode flips this to 'auto' via setEditable */
}

/* TDBLookupListBox */
/* v076: TDBLookupListBox — a data-aware lookup list. Like TDBListBox, but the rows come from a SECOND (lookup)
   dataset (listSource): each item shows the lookup's listField and carries its keyField as data-key. The item whose
   key matches the MAIN dataset's bound field (dataField) is highlighted. Display-only in browse mode (pointer-events
   are off); in edit mode the shared feed flips pointer-events on so a click moves the selection, and the chosen key
   is written to the main field on Post (see TMySQLQuery/client.js boundEditControls + dbPost). On /design the list
   is server-rendered ({DataLookupList}); in the running app the live feed re-renders it. */
.vcl-dblookuplistbox {
  box-sizing: border-box;
  background: #fff;
  border: 1px solid #7a7a7a;
  overflow: hidden;
  font: 13px Tahoma, "Segoe UI", sans-serif;
}
.vcl-dblookuplistbox-items {
  height: 100%;
  overflow-y: auto;
  pointer-events: none;   /* display-only in browse mode; edit mode flips this to 'auto' via setEditable */
}
.vcl-dblookuplistbox-item {
  padding: 1px 5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
  color: inherit;     /* inherit the model text colour (font-family/size inherited by the divs automatically) */
}
.vcl-dblookuplistbox-item:hover { background: #eaf2fb; }
.vcl-dblookuplistbox-item-sel,
.vcl-dblookuplistbox-item-sel:hover { background: #0a64c0; color: #fff; }
/* empty / unbound (no lookup rows): a faint hint so the box doesn't read as broken */
.vcl-dblookuplistbox-items:empty::before {
  content: "(no data)";
  display: block;
  padding: 2px 5px;
  color: #aaa;
  font-style: italic;
}

/* TDBMemo */
/* v078: TDBMemo — a data-aware MULTI-LINE edit (the <textarea> sibling of TDBEdit). On /design its content is the
   LIVE bound field value (the {DataFieldValue} token, resolved through designDbUnit), or a [fieldName] placeholder
   when the query isn't open. Display-only in browse mode (readonly attr); the shared feed unlocks it in edit mode
   and writes the value back to the field on Post (see TMySQLQuery/client.js refreshDbControls + boundEditControls).
   Geometry/surface come from the {Style} chain. */
.vcl-dbmemo {
  box-sizing: border-box;
  display: flex;
  background: #fff;
  border: 1px solid #7a7a7a;
  overflow: hidden;
  font: 13px Tahoma, "Segoe UI", sans-serif;   /* FALLBACK — the inline {Style} FontCss overrides when the model sets font */
  color: #000;
}
.vcl-dbmemo-input {
  flex: 1 1 auto;
  width: 100%;
  min-width: 0;
  border: none;
  outline: none;
  resize: none;
  background: transparent;
  font: inherit;     /* inherit the wrapper's font (model fontFamily/fontSize/bold/...) */
  color: inherit;    /* and the model text colour */
  padding: 2px 4px;
  white-space: pre-wrap;   /* wordWrap=True (default): wrap long lines */
}
/* wordWrap=False -> don't wrap; scroll horizontally instead */
.vcl-dbmemo-input[data-wordwrap="False"] { white-space: pre; overflow-x: auto; }

/* TDBNavigator */
/* v052: TDBNavigator — a row of dataset navigation buttons (First / Prior / Next / Last / Refresh). Each
   button drives the bound dataset through window.__tpDb (see TDBNavigator/client.js), so clicking moves the
   shared cursor and every data-aware control bound to the same query updates live. Classic VCL navigator look:
   small raised gray buttons in a row. */
.vcl-dbnav {
  box-sizing: border-box;
  display: inline-flex;
  align-items: stretch;
  gap: 0;
  background: #f0f0f0;
  border: 1px solid #a0a0a0;
  border-radius: 3px;
  overflow: hidden;
  font: 13px "Segoe UI Symbol", Tahoma, sans-serif;
  user-select: none;
}
.vcl-dbnav-btn {
  flex: 1 1 0;
  min-width: 0;
  border: none;
  border-right: 1px solid #c8c8c8;
  background: linear-gradient(#fdfdfd, #e6e6e6);
  color: #222;
  cursor: pointer;
  padding: 0 6px;
  line-height: 1;
  font: inherit;
}
.vcl-dbnav-btn:last-child { border-right: none; }
.vcl-dbnav-btn:hover  { background: linear-gradient(#ffffff, #eaf2fb); }
.vcl-dbnav-btn:active { background: linear-gradient(#dcdcdc, #cfcfcf); }

/* TDBQRCode */
/* TDBQRCode — data-aware QR code. Host carries the geometry (inline {Style}); client.js renders a
   crisp SVG of the bound field's value, refreshed as the dataset cursor moves. On /design (no
   client.js) the static template SVG skeleton is shown. */

.vcl-dbqrcode {
  box-sizing: border-box;
  display: block;
  overflow: hidden;
  background: transparent;
  line-height: 0;
}
.vcl-dbqrcode > svg { display: block; width: 100%; height: 100%; }

/* TDBRadioGroup */
/* v055: TDBRadioGroup — radio options from its `items` (one per line); the option equal to the bound field value
   is selected (the {DataFieldRadios} token; the live feed re-checks the match). Display-only (pointer-events:none)
   — the runtime write-back (Post) is a later step. */
.vcl-dbradiogroup {
  box-sizing: border-box;
  border: 1px solid #a0a0a0;
  border-radius: 3px;
  margin: 0;
  padding: 2px 8px 6px;
  background: #f0f0f0;
  font: 13px Tahoma, "Segoe UI", sans-serif;
  color: #000;
  overflow: auto;
}
.vcl-dbradiogroup-cap {
  padding: 0 4px;
  font-weight: 600;
}
.vcl-dbradiogroup-items {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding-top: 2px;
}
.vcl-dbradiogroup-item {
  display: flex;
  align-items: center;
  gap: 5px;
  white-space: nowrap;
  cursor: default;
}
.vcl-dbradiogroup-item input {
  pointer-events: none;   /* display-only */
  margin: 0;
  flex: 0 0 auto;
}

/* TDBRichEdit */
/* v081: TDBRichEdit — a rich-text EDITOR bound to a field. The body is a contenteditable div rendering the field's
   HTML; the user edits it (native rich text: Ctrl+B/I/U, paste-with-formatting) and on BLUR the edited innerHTML is
   written back to the field + Posted (autoEdit-style — like the v079 date picker; no edit/post buttons needed). A
   readOnly TDBRichEdit is not editable (contenteditable=false). The editable sibling of TDBHTMLText (read-only).
   On /design the field HTML is server-rendered ({DataFieldHtml}); the running app re-fills the body live (but never
   while it's focused, so it can't clobber a mid-edit). Geometry/surface come from the {Style} chain. */
.vcl-dbrichedit {
  box-sizing: border-box;
  background: #fff;
  border: 1px solid #7a7a7a;
  overflow: auto;
  font: 13px Tahoma, "Segoe UI", sans-serif;   /* FALLBACK — the {Style} FontCss overrides when the model sets font */
  color: #000;
}
.vcl-dbrichedit-body {
  min-height: 100%;
  padding: 3px 6px;
  outline: none;
  cursor: text;
  font: inherit;     /* inherit the wrapper's font (model fontFamily/fontSize/bold/...) */
  color: inherit;    /* and the model text colour */
}
.vcl-dbrichedit-body:focus { box-shadow: inset 0 0 0 2px #0a64c0; }
.vcl-dbrichedit-body > :first-child { margin-top: 0; }
.vcl-dbrichedit-body > :last-child { margin-bottom: 0; }
.vcl-dbrichedit-body img { max-width: 100%; }

/* TDBText */
/* v055: TDBText — a read-only label showing the bound field's current value (the {DataFieldValue} token; the
   live feed re-renders its text). On /design it shows the value or a [fieldName] placeholder. */
.vcl-dbtext {
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  overflow: hidden;
  font: 13px Tahoma, "Segoe UI", sans-serif;   /* FALLBACK — the {Style} FontCss overrides when the model sets font */
  color: #000;
}
.vcl-dbtext-val {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.vcl-dbtext-val:empty::before { content: ""; }

/* TMySQLDatabase */
/* v048: shared NON-VISUAL component "puck" — the design-time icon for data comps that have no icon
   image of their own (TMySQLDatabase, TMySQLQuery, and any future Data-tab non-visual comp). It mirrors
   the reference IDE's default placeholder puck: a muted dashed tile with a small centred box glyph.

   IMPORTANT: the comp's BOX (its width/height + selection bounds) is ONLY the 24x24 puck. The instance
   name is rendered as an ::after label that's absolutely positioned BELOW the puck (out of flow), so it
   never enlarges the box. Both Data-tab styles.css files load together via /components.css, so this base
   rule is always present even if only one comp is on the form. Hidden by default (display:none) so the
   RUNNING app never shows the puck; /design injects `.vcl-nonvisual { display:block !important }` (see
   ServeDesign) to reveal it. The name comes from data-tp-name via ::after — NOT textContent — so the
   worker's FCaption='' boot delta can't wipe it. */
.vcl-nonvisual {
  display: none;
  box-sizing: border-box;
  cursor: pointer;
  user-select: none;
  overflow: visible;
  /* the 24x24 placeholder puck — dashed tile (#E4E7EC fill, #969CA5 dashed border) + centred box glyph
     (#C4C9D0 fill, #787E88 border). An inline SVG so it needs no image file (matches the ref's internally
     drawn placeholder.png). Painted on the box itself: the box IS the puck. */
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Crect x='.5' y='.5' width='23' height='23' fill='%23E4E7EC' stroke='%23969CA5' stroke-dasharray='3 2'/%3E%3Crect x='8' y='8' width='8' height='8' fill='%23C4C9D0' stroke='%23787E88'/%3E%3C/svg%3E") center / 24px 24px no-repeat;
}
/* the instance name, floated BELOW the puck box (absolute → does not affect the box size/selection). */
.vcl-nonvisual::after {
  content: attr(data-tp-name);
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  margin-top: 2px;
  font: 11px/1.2 Tahoma, "Segoe UI", sans-serif;
  color: #000;
  white-space: nowrap;
  pointer-events: none;
}

/* TMySQLDirectQuery */
/* v075: TMySQLDirectQuery uses the shared non-visual "puck" — its styling (the dashed placeholder tile +
   centred name) lives in components/Data/TMySQLDatabase/styles.css under .vcl-nonvisual. No per-comp icon:
   the data comps share the default puck and are distinguished by their name label. */

/* TButton */
/* v376 (port tsw2 v305, css-import.txt M3/S4): colour literals flow through the --tp-* theme tokens; every
   fallback is the exact pre-v376 literal, so with no token theme the look is pixel-identical. W's button base
   is a single background gradient (no solid base + gradient-image split like tsw2), so it maps to the base
   gradient token --tp-grad-button; --tp-btn-bg (a solid) is consumed by the header sign-in buttons instead. */
.vcl-button {
  cursor: pointer;
  border: 1px solid transparent;            /* transparent ring for the inset look */
  border-radius: 3px;
  background: var(--tp-grad-button, linear-gradient(to bottom, #f5f5f5, #dcdcdc));
  background-clip: padding-box;
  box-shadow: inset 0 0 0 1px var(--tp-btn-ring, rgb(173, 173, 173));
  color: var(--tp-btn-fg, #1a1a1a);
  font: 11px Tahoma, sans-serif;
  box-sizing: border-box;
}
.vcl-button:hover:not(:disabled) {
  background: var(--tp-grad-button-hover, linear-gradient(to bottom, #e8f0fe, #c2d4f8));
  box-shadow: inset 0 0 0 1px var(--tp-accent, #4a7abf);
}
.vcl-button:active:not(:disabled) {
  background: var(--tp-grad-button-active, linear-gradient(to bottom, #c2d4f8, #e8f0fe));
}
.vcl-button:disabled { cursor: not-allowed; opacity: 0.55; }

/* TCheckBox */
/* TCheckBox — box + caption laid out in a flex row (from the reference classic.css). The geometry
   mirror sizes the <label> (data-tp-name host); the <input> is sized in em so it tracks the font. */
.vcl-checkbox {
  display: flex;
  align-items: center;
  gap: 6px;
}
.vcl-checkbox > input {
  margin: 0;
  font: inherit;
  width: 1em !important;
  height: 1em !important;
  flex: 0 0 auto;
}

/* TComboBox */
/* TComboBox — a plain (non-editable, csDropDownList-style) dropdown. The {ItemsOptions} token renders its
   <option>s server-side, selected by the DFM's ItemIndex; runtime selection changes mirror live (v313). */
.vcl-combobox {
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  border: 1px solid #7a7a7a;
  background: #fff;
  font: 13px Tahoma, "Segoe UI", sans-serif;   /* fallback — {Style} FontCss overrides when the model sets font */
  color: #000;
  padding: 1px 3px;
}

/* TEdit */
/* v376 (port tsw2 v305): theme tokens, fallbacks = pre-v376 literals. NB a real dropped TEdit also gets an
   inline background/border from BevelCssFromDfm (routed through --tp-def-tedit-*), which beats these; these
   remain the fallback for any TEdit that does not go through the surface path. */
.vcl-edit {
  background: var(--tp-input-bg, #fff);
  border: 1px solid var(--tp-input-border, rgb(173, 173, 173));
  font: 11px Tahoma, sans-serif;
  box-sizing: border-box;
}

/* TGroupBox */
/* TGroupBox — bordered group with the caption in the <legend> (from the reference classic.css). */
.vcl-groupbox {
  border: 1px solid var(--tp-border, #888);   /* v376: theme token */
  background: transparent;
  margin: 0;
  padding: 0;
}
.vcl-groupbox > legend {
  padding: 0 4px;
  font: inherit;
}

/* TLabel */
.vcl-label {
  background: transparent;
  font: 11px Tahoma, sans-serif;
  color: var(--tp-fg, #1a1a1a);   /* v305: theme token */
}

/* TListBox */
/* TListBox — a single-select scrollable list. `size="5"` in the template forces multi-row rendering (a plain
   <select> with size<=1 collapses to a dropdown); the geometry {Style} height then clips/scrolls it to the
   dropped size, same as any other comp. MultiSelect (the `multiple` attribute) is a later version. */
.vcl-listbox {
  box-sizing: border-box;
  width: 100%;
  height: 100%;
  border: 1px solid #7a7a7a;
  background: #fff;
  font: 13px Tahoma, "Segoe UI", sans-serif;   /* fallback — {Style} FontCss overrides when the model sets font */
  color: #000;
  padding: 0;
  overflow-y: auto;
}

/* TMemo */
.vcl-memo {
  background: var(--tp-input-bg, #fff);   /* v376: theme token; a real memo's inline BevelCss (--tp-def-tmemo-*) still overrides bg/border */
  font: 11px Tahoma, sans-serif;
  box-sizing: border-box;
  padding: 1px 2px;
  resize: none;
  overflow: auto;
  white-space: pre-wrap;
}

/* TPanel */
/* TPanel — caption centered behind any children. v102: the static raised-bevel hack
   (.vcl-panel--outer-raised) is GONE; BevelCssFromDfm now emits background/border/box-shadow
   inline from the comp's Color/BorderStyle/Bevel* props (a fresh panel still gets its defaults). */
.vcl-panel {
  background: var(--tp-surface-2, #f0f0f0);   /* v376: theme token; a real panel's inline BevelCss (--tp-def-tpanel-bg) still overrides bg */
  box-sizing: border-box;
}
.vcl-panel-cap {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  color: inherit;
}

/* TRadioButton */
/* TRadioButton — same flex row as the checkbox (from the reference classic.css). */
.vcl-radio {
  display: flex;
  align-items: center;
  gap: 6px;
}
.vcl-radio > input {
  margin: 0;
  font: inherit;
  width: 1em !important;
  height: 1em !important;
  flex: 0 0 auto;
}

/* TRadioGroup */
/* TRadioGroup — bordered group of radio options (Items.Strings), one checked via ItemIndex. Interactive sibling
   of TDBRadioGroup's display-only vcl-dbradiogroup (that one is pointer-events:none — a live bound field renders
   it, per the db-parity-convergence memory; this one has no DataSource, so clicking a radio is the only way to
   change ItemIndex, same as real Delphi). */
.vcl-radiogroup {
  box-sizing: border-box;
  border: 1px solid #a0a0a0;
  border-radius: 3px;
  margin: 0;
  padding: 2px 8px 6px;
  background: transparent;
  font: 13px Tahoma, "Segoe UI", sans-serif;
  color: #000;
  overflow: auto;
}
.vcl-radiogroup > legend {
  padding: 0 4px;
  font-weight: 600;
}
.vcl-radiogroup-items {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding-top: 2px;
}
.vcl-radiogroup-item {
  display: flex;
  align-items: center;
  gap: 5px;
  white-space: nowrap;
  cursor: pointer;
}

/* TDateTimePicker */
.vcl-datetimepicker {
  box-sizing: border-box;
  border: 1px solid #7a7a7a;
  background: #fff;
  font: 11px Tahoma, sans-serif;
}

/* TListView */
.vcl-listview {
  box-sizing: border-box;
  border: 1px solid #7a7a7a;
  background: #fff;
  font: 11px Tahoma, sans-serif;
  overflow: auto;
}
.vcl-listview-hdr {
  display: flex;
  background: #f0f0f0;
  border-bottom: 1px solid #d0d0d0;
  position: sticky;
  top: 0;
}
.vcl-listview-hdr > span {
  flex: 1;
  padding: 2px 6px;
  border-right: 1px solid #d0d0d0;
  font-weight: normal;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.vcl-listview-row {
  display: flex;
  cursor: default;
}
.vcl-listview-row > span {
  flex: 1;
  padding: 1px 6px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* v225: gridlines + row selection (built by the package client.js at runtime) */
.vcl-listview-gridlines .vcl-listview-row > span { border-right: 1px solid #e4e4e4; border-bottom: 1px solid #e4e4e4; }
.vcl-listview-row:hover { background: #f2f7fd; }
.vcl-listview-row.vcl-listview-sel { background: #cbe4fb; }
.vcl-listview-row.vcl-listview-sel > span { color: #000; }

/* TPageControl */
.vcl-pagecontrol {
  box-sizing: border-box;
  border: 1px solid #a0a0a0;
  background: #fff;
  padding: 2px;
}

/* The tab strip + page framing are built by the package client.js at runtime (design view stays inert).
   Cloned from tswebide2's TPageControl visual (the reference look). */
.vcl-pc-tabbar {
  position: absolute;
  left: 0; top: 0; right: 0;
  height: 26px;
  display: flex;
  flex-direction: row;
  align-items: flex-end;
  gap: 2px;
  padding: 0 4px;
  box-sizing: border-box;
  border-bottom: 2px solid #0078d7;
  font: 11px Tahoma, sans-serif;
  background: #f0f0f0;
  z-index: 2;
}
.vcl-pc-tab {
  padding: 3px 12px;
  cursor: pointer;
  border: 1px solid #ccc;
  border-bottom: none;
  border-radius: 4px 4px 0 0;
  background: #e8e8e8;
  color: #444;
  user-select: none;
  white-space: nowrap;
}
.vcl-pc-tab:hover:not(.vcl-pc-tab-active) { background: #dcdcdc; }
.vcl-pc-tab-active {
  background: #ffffff;
  border-color: #0078d7;
  color: #000;
  font-weight: bold;
  position: relative;
  bottom: -2px;
}

/* TProgressBar */
.vcl-progressbar {
  box-sizing: border-box;
  -webkit-appearance: none;
  appearance: none;
  border: 1px solid #bcbcbc;
  background: #e6e6e6;
  vertical-align: top;
}
.vcl-progressbar::-webkit-progress-bar { background: #e6e6e6; }
.vcl-progressbar::-webkit-progress-value { background: #06b025; }
.vcl-progressbar::-moz-progress-bar { background: #06b025; }

/* TRichEdit */
.vcl-richedit {
  box-sizing: border-box;
  border: 1px solid #7a7a7a;
  background: #fff;
  font: 11px Tahoma, sans-serif;
  overflow: auto;
  padding: 2px;
}

/* TStatusBar */
.vcl-statusbar {
  box-sizing: border-box;
  border-top: 1px solid #808080;
  background: #f0f0f0;
  display: flex;
  align-items: center;
  padding: 2px 6px;
  font: 11px Tahoma, sans-serif;
  color: #000;
}

/* TTabControl */
.vcl-tabcontrol {
  box-sizing: border-box;
  border: 1px solid #a0a0a0;
  background: #fff;
  padding: 2px;
}

/* The tab strip is built by the package client.js at runtime (design view stays inert). Cloned from
   tswebide2's TPageControl look; single shared client area (no per-tab pages). */
.vcl-tc-tabbar {
  position: absolute;
  left: 0; top: 0; right: 0;
  height: 26px;
  display: flex;
  flex-direction: row;
  align-items: flex-end;
  gap: 2px;
  padding: 0 4px;
  box-sizing: border-box;
  border-bottom: 2px solid #0078d7;
  font: 11px Tahoma, sans-serif;
  background: #f0f0f0;
  z-index: 2;
}
.vcl-tc-tab {
  padding: 3px 12px;
  cursor: pointer;
  border: 1px solid #ccc;
  border-bottom: none;
  border-radius: 4px 4px 0 0;
  background: #e8e8e8;
  color: #444;
  user-select: none;
  white-space: nowrap;
}
.vcl-tc-tab:hover:not(.vcl-tc-tab-active) { background: #dcdcdc; }
.vcl-tc-tab-active {
  background: #ffffff;
  border-color: #0078d7;
  color: #000;
  font-weight: bold;
  position: relative;
  bottom: -2px;
}

/* TTabSheet */
.vcl-tabsheet {
  box-sizing: border-box;
  background: #fff;
}

/* TToolBar */
.vcl-toolbar {
  box-sizing: border-box;
  border-bottom: 1px solid #a0a0a0;
  background: #f0f0f0;
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 2px;
}

/* TToolButton */
.vcl-toolbutton {
  box-sizing: border-box;
  border: 1px solid transparent;
  background: transparent;
  font: 11px Tahoma, sans-serif;
  padding: 2px 8px;
  cursor: default;
}
.vcl-toolbutton:hover {
  border-color: #b0b0b0;
  background: #e8e8e8;
}

/* TTrackBar */
.vcl-trackbar {
  box-sizing: border-box;
  vertical-align: top;
}

/* TTreeView */
.vcl-treeview {
  box-sizing: border-box;
  border: 1px solid #7a7a7a;
  background: #fff;
  font: 11px Tahoma, sans-serif;
  overflow: auto;
  padding: 2px;
}
.vcl-tree-node {
  display: flex;
  align-items: center;
  padding: 1px 4px;
  white-space: nowrap;
  cursor: default;
}
.vcl-tree-node:hover { background: #f2f7fd; }
.vcl-tree-node.vcl-tree-sel { background: #cbe4fb; color: #000; }
.vcl-tree-caret {
  display: inline-block;
  width: 14px;
  text-align: center;
  cursor: pointer;
  color: #555;
  flex: 0 0 auto;
  user-select: none;
}
.vcl-tree-caret.vcl-tree-leaf { cursor: default; color: transparent; }
.vcl-tree-label { flex: 1 1 auto; }
/* legacy static-mockup class (design view); runtime rebuilds innerHTML */
.vcl-tree-sub { padding-left: 20px; }

