/* ==========================================================================
   ttk.css — the Tomasetti Tech Kit (the house UI design language, zero deps)

   WHAT THIS IS
   The house interactive layer: foundations (tokens, type, motion, states) plus
   the component library, extracted from ui-kit.html so it can drop onto any
   surface. Every selector is `ttk-` prefixed, so it never collides with an
   app's own CSS.

   NAMING: this kit was called "stolen moves" while it was a one-page demo of
   techniques harvested from other people's sites. It is the house language
   now, so it is named after the house. Tj, 2026-09-27: "if we could not call
   it stolen moves anymore that would be cool". Showcase: ui-kit.html.

   Tj's standing rule (2026-09-26): this is the DEFAULT interactive layer for
   every Tomasetti surface. A page that doesn't look finished is usually
   missing components, not copy. When Tj says "use the new UI components",
   he means THESE. Canon: docs/UI-KIT.md

   COLOUR: every value routes through the house tokens (--t-*) with the dark
   kit values as fallbacks, so the same file works on the dark portals and on
   the light office surfaces without a second theme file.

   USAGE: <link rel="stylesheet" href="/assets/ttk.css">
          <script src="/assets/ttk.js" defer></script>
   Auto-inits on DOMContentLoaded. Call TTK.init(el) for content injected later.

   VERSION 2.1.0 — foundations + 52 components (batch 4: the commerce set, 09-27)
   + the smoothness pass: spring idle-stop, overlay open-stack, left-drawer
   fix, palette focus, scrollbar-shift compensation, reduced-motion completions.
   ========================================================================== */

:root{
  --ttk-bg:      var(--t-bg, #14121a);
  --ttk-surface: var(--t-card-bg, var(--t-surface, #1c1926));
  --ttk-raised:  var(--t-panel, var(--t-surface, #221e2e));
  --ttk-ink:     var(--t-ink, #ece9f4);
  --ttk-muted:   var(--t-ink-mute, #9d97b0);
  --ttk-accent:  var(--t-accent, #b9a8ff);
  --ttk-line:    var(--t-line, rgba(236,233,244,.14));
  --ttk-on-accent: #14121a;
  --ttk-sans:    var(--t-font-ui, -apple-system, "Segoe UI", Roboto, "Outfit", Helvetica, Arial, sans-serif);
  --ttk-mono:    var(--t-font-mono, "Cascadia Code", "Share Tech Mono", Consolas, monospace);
  --ttk-r:       var(--t-radius, 12px);
  --ttk-shadow:  0 12px 34px rgba(0,0,0,.28);
}

/* ── theme bridge ─────────────────────────────────────────────────────────
   The office surfaces (books, crm, the portals) do NOT speak --t-*: they
   carry --tt-office-* instead, whose accent is a deep violet (#6036b8) and
   whose panel in light mode is #fff. Reading the retired --t-* set on those
   pages produced a dark button on a white page. This block maps the kit onto
   the office tokens when they are present, and leaves the dark defaults
   above untouched everywhere else (the kit page itself sets neither).
   White rides on the office accent; the dark kit's own lilac keeps dark ink.
   An app can still override any --ttk-* by declaring it after this file. */
html[data-tt-family]{
  --ttk-bg:      var(--tt-office-canvas, #14121a);
  --ttk-surface: var(--tt-office-panel, #1c1926);
  --ttk-raised:  var(--tt-office-panel, #221e2e);
  --ttk-ink:     var(--tt-office-ink, #ece9f4);
  --ttk-muted:   var(--tt-office-ink-muted, #9d97b0);
  --ttk-accent:  var(--tt-office-accent, #b9a8ff);
  --ttk-line:    var(--tt-office-line, rgba(236,233,244,.14));
  --ttk-on-accent: #fff;
}

/* ── 01 jelly toolbar ───────────────────────────────────────────────────── */
.ttk-jelly{position:relative}
/* the pill chassis is the TOOLBAR's. A bare rail is an overlay on a host nav,
   so it must not set display/gap/padding/background/border-radius — at equal
   specificity the kit (loaded after the host) would out-rank the host's own
   layout and flatten it. */
.ttk-jelly:not(.ttk-jelly-bare){display:inline-flex;gap:4px;background:var(--ttk-raised);
  border:1px solid var(--ttk-line);border-radius:999px;padding:6px}
.ttk-jelly-goo{position:absolute;inset:0;filter:url(#ttk-goo)}
.ttk-jelly-blob{position:absolute;left:0;top:50%;width:80px;height:40px;
  border-radius:var(--ttk-jelly-r,999px);
  background:var(--ttk-accent);transform:translate(0,-50%)}
/* NOTE: no `color` here. This rule used to carry `color:var(--ttk-muted)`, and
   because the kit loads AFTER the host's stylesheet an equal-specificity rule
   wins — which flattened every sidebar link to one muted shade. On the office
   rail (a dark violet) that was the LIGHT theme's ink-muted, i.e. dark ink on
   dark: the "sidebar is hard to read" complaint. Colour is set below, for the
   toolbar variant only. */
.ttk-jelly-item{position:relative;z-index:1;border:0;background:none;cursor:pointer;
  transition:color .18s;text-decoration:none;font:600 13.5px var(--ttk-sans);
  display:inline-flex;align-items:center;gap:7px}
.ttk-jelly-item:focus-visible{outline:2px solid var(--ttk-accent);outline-offset:2px}
/* colours belong to the TOOLBAR variant only. In bare mode the kit contributes
   no colour at all: a sidebar link already has the host's own palette (the
   office shell paints its rail white and marks the current page itself), and
   a kit rule here would out-rank the host's aria-current state and flatten
   the text to one shade. Bare mode = the melting highlight, nothing else. */
.ttk-jelly:not(.ttk-jelly-bare) .ttk-jelly-item{padding:9px 16px;border-radius:999px;
  color:var(--ttk-muted)}
.ttk-jelly:not(.ttk-jelly-bare) .ttk-jelly-item:hover,
.ttk-jelly:not(.ttk-jelly-bare) .ttk-jelly-item.on{color:var(--ttk-on-accent)}
/* vertical rail: the blob becomes a full-width bar that slides down the track */
.ttk-jelly[data-axis="y"] .ttk-jelly-blob{top:0;transform:translate(0,0)}
.ttk-jelly[data-axis="y"]:not(.ttk-jelly-bare){flex-direction:column;gap:2px;width:100%}
.ttk-jelly[data-axis="y"]:not(.ttk-jelly-bare) .ttk-jelly-item{text-align:left;
  justify-content:flex-start}
/* bare mode = the highlight, nothing else. Layout, padding, radius, colour and
   type all belong to the host nav; the kit contributes one blob. `--ttk-jelly-r`
   MUST match the host's row radius (10px on the office rail) or the highlight
   reads as a pill sitting inside a box — Tj: "this doesn't look good". */
.ttk-jelly.ttk-jelly-bare{--ttk-jelly-r:10px}

/* ── 02 magnetic buttons ────────────────────────────────────────────────── */
.ttk-mag-zone{display:inline-flex;padding:12px}
/* will-change is scoped to zone hover, not the resting page: a dashboard with
   six magnetic buttons must not carry six permanent compositor layers. The
   button only moves while the pointer is inside its zone anyway. */
.ttk-mag{border:0;border-radius:999px;background:var(--ttk-accent);color:var(--ttk-on-accent);
  font:600 14.5px var(--ttk-sans);padding:14px 28px;cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;text-decoration:none;line-height:1.2}
.ttk-mag-zone:hover .ttk-mag,.ttk-mag-zone:hover .ttk-mag span{will-change:transform}
.ttk-mag span{display:inline-block}
.ttk-mag-ghost{border:1px solid var(--ttk-accent);background:transparent;color:var(--ttk-ink)}

/* ── 03 per-letter hover wave ───────────────────────────────────────────── */
.ttk-wave{border:1px solid var(--ttk-line);background:var(--ttk-raised);color:var(--ttk-ink);
  font:600 14.5px var(--ttk-sans);padding:13px 24px;border-radius:999px;cursor:pointer}
.ttk-wave .ttk-l{display:inline-block;transition:transform .3s cubic-bezier(.2,.7,.3,1.5)}
.ttk-wave:hover .ttk-l{transform:translateY(-.32em)}

/* ── 04 elastic dropdown ────────────────────────────────────────────────── */
.ttk-dd{position:relative;display:inline-block}
.ttk-dd-btn{border:1px solid var(--ttk-line);background:var(--ttk-raised);color:var(--ttk-ink);
  font:600 13.5px var(--ttk-sans);padding:11px 18px;border-radius:10px;cursor:pointer;
  display:inline-flex;align-items:center;gap:8px}
.ttk-dd-btn::after{content:"\25BE";color:var(--ttk-accent);font-size:11px}
.ttk-dd.open .ttk-dd-btn{border-color:var(--ttk-accent)}
.ttk-dd-menu{position:absolute;top:calc(100% + 8px);left:0;min-width:210px;background:var(--ttk-raised);
  border:1px solid var(--ttk-line);border-radius:var(--ttk-r);padding:6px;transform:scaleY(0);
  transform-origin:50% 0;z-index:60;box-shadow:var(--ttk-shadow);max-height:340px;overflow:auto}
.ttk-dd-i{display:block;width:100%;text-align:left;border:0;background:none;color:var(--ttk-muted);
  font:500 13.5px var(--ttk-sans);padding:9px 12px;border-radius:8px;cursor:pointer;
  opacity:0;transform:translateY(-6px);
  transition:opacity .18s,transform .18s,color .15s,background .15s}
.ttk-dd.open .ttk-dd-i{opacity:1;transform:none}
.ttk-dd-i:nth-child(1){transition-delay:.04s}.ttk-dd-i:nth-child(2){transition-delay:.07s}
.ttk-dd-i:nth-child(3){transition-delay:.1s}.ttk-dd-i:nth-child(4){transition-delay:.13s}
.ttk-dd-i:nth-child(5){transition-delay:.16s}.ttk-dd-i:nth-child(6){transition-delay:.19s}
.ttk-dd-i:hover{color:var(--ttk-ink);background:color-mix(in srgb, var(--ttk-ink) 7%, transparent)}
.ttk-dd-i.on{color:var(--ttk-accent)}

/* ── 05 drag to reorder ─────────────────────────────────────────────────── */
.ttk-drag{display:flex;flex-direction:column;gap:8px}
.ttk-dr{display:flex;align-items:center;gap:10px;background:var(--ttk-raised);
  border:1px solid var(--ttk-line);border-radius:10px;padding:12px 14px;
  font:500 13.5px var(--ttk-sans);color:var(--ttk-muted);cursor:grab;user-select:none;
  touch-action:none}
.ttk-dr .ttk-n{font-family:var(--ttk-mono);font-size:10.5px;color:var(--ttk-accent)}
.ttk-dr.ttk-dragging{cursor:grabbing;border-color:var(--ttk-accent);
  box-shadow:0 10px 30px color-mix(in srgb, var(--ttk-accent) 32%, transparent);z-index:2}

/* ── 06 pagination pills ────────────────────────────────────────────────── */
.ttk-pager{position:relative;display:inline-flex;align-items:center;gap:2px;background:var(--ttk-raised);
  border:1px solid var(--ttk-line);border-radius:999px;padding:5px}
.ttk-pg-ind{position:absolute;left:0;top:5px;bottom:5px;width:36px;border-radius:999px;
  background:var(--ttk-accent);will-change:transform}
.ttk-pg,.ttk-pg-arrow{position:relative;z-index:1;border:0;background:none;color:var(--ttk-muted);
  font:600 13px var(--ttk-sans);min-width:34px;height:32px;border-radius:999px;cursor:pointer;
  transition:color .18s;padding:0 8px;text-decoration:none;display:inline-flex;
  align-items:center;justify-content:center}
.ttk-pg.on{color:var(--ttk-on-accent)}
.ttk-pg-arrow{font-family:var(--ttk-mono)}
.ttk-pg:hover,.ttk-pg-arrow:hover{color:var(--ttk-ink)}
.ttk-pg.on:hover{color:var(--ttk-on-accent)}
.ttk-pg[aria-disabled="true"],.ttk-pg-arrow[aria-disabled="true"]{opacity:.35;cursor:default}

/* ── 07 OTP input ───────────────────────────────────────────────────────── */
.ttk-otp{position:relative;display:inline-flex;gap:8px;cursor:text}
.ttk-ot-c{width:44px;height:54px;background:var(--ttk-raised);border:1px solid var(--ttk-line);
  border-radius:10px;display:flex;align-items:center;justify-content:center;
  font:600 20px var(--ttk-mono);color:var(--ttk-ink);transition:border-color .15s}
.ttk-ot-c.ttk-cur{border-color:var(--ttk-accent)}
.ttk-otp.ttk-done .ttk-ot-c{border-color:var(--ttk-accent)}
.ttk-otp-ind{position:absolute;bottom:-8px;left:0;width:44px;height:3px;border-radius:2px;
  background:var(--ttk-accent);will-change:transform}
.ttk-otp-in{position:absolute;opacity:0;pointer-events:none}

/* ── 08 liquid scroll rail ──────────────────────────────────────────────── */
.ttk-rail{position:fixed;right:14px;top:50%;transform:translateY(-50%);width:8px;height:180px;
  background:var(--ttk-raised);border:1px solid var(--ttk-line);border-radius:99px;z-index:40}
.ttk-rail-fill{position:absolute;left:0;right:0;bottom:0;width:100%;height:0;
  background:var(--ttk-accent);border-radius:99px}
.ttk-rail-dot{position:absolute;left:50%;top:0;width:10px;height:10px;margin-left:-5px;border-radius:50%;
  background:var(--ttk-accent)}
@media (max-width:900px){.ttk-rail{display:none}}

/* ── 09 numbers that land ───────────────────────────────────────────────── */
.ttk-count{font-variant-numeric:tabular-nums}

/* ── 10 tabs ────────────────────────────────────────────────────────────── */
.ttk-tabs{width:100%}
.ttk-tab-row{position:relative;display:flex;gap:2px;border-bottom:1px solid var(--ttk-line);
  padding:0 2px;overflow-x:auto;scrollbar-width:none}
.ttk-tab-row::-webkit-scrollbar{display:none}
.ttk-tab-ind{position:absolute;bottom:-1px;left:0;height:2px;background:var(--ttk-accent);
  border-radius:2px;will-change:transform;width:40px}
.ttk-tab{position:relative;border:0;background:none;color:var(--ttk-muted);
  font:600 13px var(--ttk-sans);padding:9px 13px;cursor:pointer;transition:color .18s;white-space:nowrap}
.ttk-tab:hover{color:var(--ttk-ink)}
.ttk-tab.on{color:var(--ttk-ink)}
.ttk-tab .ttk-badge{font-family:var(--ttk-mono);font-size:10.5px;opacity:.72;margin-left:5px}
.ttk-panel{display:none;padding:16px 2px 0}
.ttk-panel.on{display:block;animation:ttkPanelIn .28s cubic-bezier(.2,.7,.2,1)}
@keyframes ttkPanelIn{from{opacity:0;transform:translateY(6px)}}

/* ── 11 accordion ───────────────────────────────────────────────────────── */
.ttk-accwrap{width:100%;display:flex;flex-direction:column;gap:8px}
.ttk-acc{background:var(--ttk-raised);border:1px solid var(--ttk-line);border-radius:10px;overflow:hidden}
.ttk-acc-h{display:flex;justify-content:space-between;align-items:center;width:100%;border:0;
  background:none;color:var(--ttk-ink);font:600 13px var(--ttk-sans);padding:12px 14px;
  cursor:pointer;text-align:left;gap:12px}
.ttk-acc-c{color:var(--ttk-accent);transition:transform .3s;font-family:var(--ttk-mono);font-size:14px}
.ttk-acc.open .ttk-acc-c{transform:rotate(45deg)}
.ttk-acc-b{display:grid;grid-template-rows:0fr;transition:grid-template-rows .38s cubic-bezier(.2,.7,.2,1)}
.ttk-acc.open .ttk-acc-b{grid-template-rows:1fr}
.ttk-acc-i{overflow:hidden;min-height:0}

/* ── 12 toasts ──────────────────────────────────────────────────────────── */
/* a server flash becomes a toast: the <li> keeps the text for no-JS, and JS
   hides it once the toast has taken over (see .ttk-flash-done below) */
.ttk-toasts{position:fixed;right:18px;bottom:18px;display:flex;flex-direction:column;gap:10px;z-index:2000}
.ttk-toast{position:relative;overflow:hidden;background:var(--ttk-raised);border:1px solid var(--ttk-line);
  border-radius:var(--ttk-r);padding:12px 16px;min-width:250px;max-width:380px;box-shadow:var(--ttk-shadow);
  transform:translateX(120%);opacity:0;
  transition:transform .45s cubic-bezier(.2,.9,.25,1.18),opacity .3s;cursor:pointer}
.ttk-toast.ttk-in{transform:none;opacity:1}
.ttk-toast.ttk-out{transform:translateX(130%);opacity:0;transition:transform .3s ease-in,opacity .3s ease-in}
.ttk-toast-t{font:600 13px var(--ttk-sans);color:var(--ttk-ink)}
.ttk-toast-m{font:400 12px var(--ttk-sans);color:var(--ttk-muted);margin-top:2px}
.ttk-toast-bar{position:absolute;top:0;left:0;right:0;height:2px;background:var(--ttk-accent);
  transform-origin:left;animation:ttkBar 3.8s linear forwards}
@keyframes ttkBar{to{transform:scaleX(0)}}
.ttk-toast.ttk-good .ttk-toast-bar{background:var(--t-green, #4ade80)}
.ttk-toast.ttk-warn .ttk-toast-bar{background:var(--t-amber, #fbbf24)}
.ttk-toast.ttk-bad  .ttk-toast-bar{background:var(--t-red, #f87171)}

/* ── 13 switch with squash + stretch ────────────────────────────────────── */
.ttk-tgl{display:inline-flex;align-items:center;gap:10px;cursor:pointer;user-select:none}
.ttk-tgl input{position:absolute;opacity:0;width:0;height:0}
.ttk-tgl-t{width:46px;height:26px;border-radius:999px;background:var(--ttk-raised);
  border:1px solid var(--ttk-line);position:relative;transition:background .25s,border-color .25s;flex:none}
.ttk-tgl-k{position:absolute;top:2px;left:2px;width:20px;height:20px;border-radius:50%;
  background:var(--ttk-muted);transition:transform .35s cubic-bezier(.34,1.56,.64,1),background .25s}
.ttk-tgl input:checked + .ttk-tgl-t{background:color-mix(in srgb, var(--ttk-accent) 24%, transparent);
  border-color:var(--ttk-accent)}
.ttk-tgl input:checked + .ttk-tgl-t .ttk-tgl-k{transform:translateX(20px);background:var(--ttk-accent)}
.ttk-tgl input:not(:checked):active + .ttk-tgl-t .ttk-tgl-k{transform:scaleX(1.3);transform-origin:left center}
.ttk-tgl input:checked:active + .ttk-tgl-t .ttk-tgl-k{transform:translateX(20px) scaleX(1.3);transform-origin:right center}
.ttk-tgl-l{font:500 13.5px var(--ttk-sans);color:var(--ttk-muted);transition:color .2s}
.ttk-tgl input:checked ~ .ttk-tgl-l{color:var(--ttk-ink)}
.ttk-tgl:focus-within .ttk-tgl-t{outline:2px solid var(--ttk-accent);outline-offset:2px}

/* ── 14 headline that decodes ───────────────────────────────────────────── */
.ttk-scr{font-family:var(--ttk-mono);letter-spacing:.06em;white-space:nowrap;cursor:default}

/* ── 15 card that leans and catches light ───────────────────────────────── */
.ttk-tilt{position:relative;transition:transform .15s ease-out;transform-style:preserve-3d}
/* layer only while interacting — a grid of tilt cards each holding a permanent
   compositor layer was the GPU-memory cost of v2.0.0 */
.ttk-tilt:hover{will-change:transform}
/* the glare tints with the ACCENT, not with ink: on a light card an ink-white
   highlight is invisible, while a violet sheen reads on both themes */
.ttk-tilt::after{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;
  background:radial-gradient(280px circle at var(--ttk-gx,50%) var(--ttk-gy,50%),
    color-mix(in srgb, var(--ttk-accent) 16%, transparent), transparent 60%)}

/* ── 16 content that enters in stagger ──────────────────────────────────── */
html.ttk-js .ttk-rv{opacity:0;transform:translateY(16px);
  transition:opacity .55s cubic-bezier(.2,.7,.2,1),transform .55s cubic-bezier(.2,.7,.2,1);
  transition-delay:var(--ttk-d,0ms)}
html.ttk-js .ttk-rv.ttk-in{opacity:1;transform:none}

/* ── 17 copy that confirms ──────────────────────────────────────────────── */
.ttk-copy{display:flex;align-items:center;gap:10px;background:var(--ttk-raised);
  border:1px solid var(--ttk-line);border-radius:10px;padding:8px 10px;width:100%}
.ttk-copy code{font:500 12.5px var(--ttk-mono);color:var(--ttk-ink);flex:1;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap}
.ttk-copy-b{flex:none;border:1px solid var(--ttk-line);background:var(--ttk-surface);
  color:var(--ttk-muted);font:600 12px var(--ttk-sans);padding:7px 14px;border-radius:8px;
  cursor:pointer;transition:color .15s,border-color .15s,background .15s}
.ttk-copy-b:hover{color:var(--ttk-ink)}
.ttk-copy-b.ttk-ok{background:var(--ttk-accent);border-color:var(--ttk-accent);color:var(--ttk-on-accent)}
.ttk-copy-mini{border:1px solid var(--ttk-line);background:transparent;color:var(--ttk-muted);
  border-radius:6px;padding:3px 8px;font:600 11px var(--ttk-sans);cursor:pointer;
  transition:background .15s,color .15s,border-color .15s;vertical-align:middle;margin-left:6px}
.ttk-copy-mini:hover{color:var(--ttk-ink)}
.ttk-copy-mini.ttk-ok{background:var(--ttk-accent);border-color:var(--ttk-accent);color:var(--ttk-on-accent)}

/* ── 18 dial that springs to value ──────────────────────────────────────── */
/* size it with --ttk-ring-size / --ttk-ring-w: a 120px headline dial and a
   38px confidence chip are the same component, not two implementations.
   Give the SVG a viewBox="0 0 120 120" and it scales with the box. */
.ttk-ringbox{position:relative;width:var(--ttk-ring-size,120px);height:var(--ttk-ring-size,120px);flex:none}
.ttk-ring{display:block;width:100%;height:100%}
.ttk-ring-bg{fill:none;stroke:var(--ttk-raised);stroke-width:var(--ttk-ring-w,10)}
.ttk-ring-v{fill:none;stroke:var(--ttk-accent);stroke-width:var(--ttk-ring-w,10);stroke-linecap:round}
.ttk-ring-l{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  font:700 20px var(--ttk-mono);color:var(--ttk-ink);font-size:calc(var(--ttk-ring-size,120px) * 0.17)}

/* ── 19 brand ticker ────────────────────────────────────────────────────── */
.ttk-mq{overflow:hidden;width:100%;
  -webkit-mask-image:linear-gradient(90deg,transparent,#000 10%,#000 90%,transparent);
  mask-image:linear-gradient(90deg,transparent,#000 10%,#000 90%,transparent)}
.ttk-mq-t{display:inline-flex;gap:44px;white-space:nowrap;animation:ttkMq 20s linear infinite;
  padding-right:44px}
.ttk-mq:hover .ttk-mq-t{animation-play-state:paused}
.ttk-mq-t span{font:600 13px var(--ttk-mono);letter-spacing:.22em;color:var(--ttk-muted)}
@keyframes ttkMq{to{transform:translateX(-50%)}}

/* ==========================================================================
   VERSION 2.0.0 — BATCH 3 (2026-09-27). Foundations + 28 components.

   The kit was a pile of good tricks. A design language needs the layer UNDER
   the components — the tokens, the type rules, the motion vocabulary, the
   state matrix — because that is what makes two pages built by two different
   agents look like one product. F1-F5 are that layer; 20-47 are the missing
   primitives (forms were the biggest hole: the kit shipped ONE form control,
   the switch, while every app has inputs and selects).
   ========================================================================== */

/* ══ F1 tokens — the values, shown ═══════════════════════════════════════ */
/* Presentational only: renders whatever --t-*/--ttk-* are live, so the
   swatches are never a stale copy of the token sheet. The chip paints
   var(--c), which the author sets inline — hex is documentation, not source. */
.ttk-sws{display:grid;grid-template-columns:repeat(auto-fill,minmax(148px,1fr));gap:10px}
.ttk-sw{display:flex;align-items:center;gap:10px;background:var(--ttk-raised);border:1px solid var(--ttk-line);
  border-radius:10px;padding:9px 11px}
.ttk-sw-c{width:26px;height:26px;border-radius:8px;background:var(--c,var(--ttk-accent));flex:none;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.12)}
.ttk-sw-n{font:600 12px var(--ttk-sans);color:var(--ttk-ink);display:block;line-height:1.3}
.ttk-sw-v{font:400 10.5px var(--ttk-mono);color:var(--ttk-muted);display:block}

/* ══ F2 type — the rules, not just the fonts ═════════════════════════════ */
/* The r/webdesign harvest: "four or five weights of the same grotesk and
   nobody's touched line height or measure". These rows carry the rule. */
.ttk-type{display:flex;flex-direction:column;gap:2px}
.ttk-type-r{display:grid;grid-template-columns:168px 1fr;gap:14px;align-items:baseline;
  padding:12px 0;border-bottom:1px solid var(--ttk-line)}
.ttk-type-r:last-child{border-bottom:0}
.ttk-type-m{font:500 10.5px/1.6 var(--ttk-mono);color:var(--ttk-muted);text-transform:uppercase;
  letter-spacing:.08em}
.ttk-type-d{font:700 clamp(26px,4vw,34px)/1.06 var(--ttk-sans);color:var(--ttk-ink);
  letter-spacing:-.025em;margin:0}
.ttk-type-h{font:650 20px/1.25 var(--ttk-sans);color:var(--ttk-ink);letter-spacing:-.014em;margin:0}
.ttk-type-b{font:400 14.5px/1.62 var(--ttk-sans);color:var(--ttk-muted);max-width:68ch;margin:0}
.ttk-type-s{font:400 12.5px/1.5 var(--ttk-sans);color:var(--ttk-muted);margin:0}
.ttk-type-c{font:500 12.5px var(--ttk-mono);color:var(--ttk-accent);letter-spacing:.02em;margin:0}

/* ══ F3 motion — the springs, named and demonstrated ═════════════════════ */
/* The rule that keeps this from becoming decoration: SPRINGS CHASE MOTION,
   CSS TRANSITIONS DO STATE. A spring is for something that has to travel
   (a blob, an indicator, a value); a state change (hover, open, checked) is a
   transition, because it must be interruptible and cheap. Critical
   information never animates. Reduced motion snaps to the end. */
.ttk-mo{display:flex;flex-direction:column;gap:2px}
.ttk-mo-r{display:grid;grid-template-columns:132px 118px 1fr;gap:12px;align-items:center;
  padding:9px 0;border-bottom:1px solid var(--ttk-line)}
.ttk-mo-r:last-child{border-bottom:0}
.ttk-mo-n{font:600 12.5px var(--ttk-sans);color:var(--ttk-ink)}
.ttk-mo-s{font:400 10.5px var(--ttk-mono);color:var(--ttk-muted)}
.ttk-mo-t{position:relative;height:26px;background:var(--ttk-raised);border:1px solid var(--ttk-line);
  border-radius:99px;overflow:hidden}
.ttk-mo-d{position:absolute;top:3px;left:3px;width:20px;height:20px;border-radius:50%;
  background:var(--ttk-accent);animation:ttkMoRun 2.1s var(--ttk-mo-e,cubic-bezier(.2,.7,.2,1)) infinite}
@keyframes ttkMoRun{0%,12%{left:3px}50%,72%{left:calc(100% - 23px)}100%{left:3px}}

/* ══ F4 space / radius / elevation ══════════════════════════════════════ */
.ttk-sc{display:flex;flex-direction:column;gap:8px}
.ttk-sc-r{display:flex;align-items:center;gap:12px}
.ttk-sc-b{height:14px;background:var(--ttk-accent);border-radius:4px;width:var(--w,10px);opacity:.85}
.ttk-sc-l{font:400 11px var(--ttk-mono);color:var(--ttk-muted);min-width:104px}
.ttk-rad{display:flex;gap:12px;align-items:flex-end}
.ttk-rad-b{width:64px;height:64px;background:var(--ttk-raised);border:1px solid var(--ttk-line);
  border-radius:var(--r,10px);display:flex;align-items:flex-end;justify-content:center;
  font:400 10px var(--ttk-mono);color:var(--ttk-muted);padding-bottom:4px}
.ttk-el{display:flex;gap:16px;align-items:center}
.ttk-el-b{width:78px;height:52px;border-radius:12px;background:var(--ttk-raised);
  border:1px solid var(--ttk-line);box-shadow:var(--e,none);display:flex;align-items:center;
  justify-content:center;font:400 10px var(--ttk-mono);color:var(--ttk-muted)}

/* ══ F5 state matrix — every control answers the same six questions ══════ */
.ttk-states{width:100%;border-collapse:collapse;font:500 12.5px var(--ttk-sans)}
.ttk-states th{font:600 10.5px var(--ttk-mono);color:var(--ttk-muted);text-transform:uppercase;
  letter-spacing:.1em;text-align:left;padding:0 10px 8px 0;font-weight:600}
.ttk-states td{padding:7px 10px 7px 0;color:var(--ttk-ink);vertical-align:middle}
.ttk-states tr+tr td{border-top:1px solid var(--ttk-line)}
.ttk-states code{font:400 11px var(--ttk-mono);color:var(--ttk-muted)}
/* the house focus ring — one definition, every control inherits it */
.ttk-focus{outline:2px solid var(--ttk-accent);outline-offset:2px}

/* ── 20 floating-label field ────────────────────────────────────────────── */
/* Pure CSS: `placeholder=" "` is what lets :placeholder-shown carry the
   "empty" state, so the label floats without a line of JS. */
.ttk-field{position:relative;display:block;margin:0 0 16px}
.ttk-field>input,.ttk-field>textarea{width:100%;box-sizing:border-box;background:var(--ttk-raised);
  border:1px solid var(--ttk-line);border-radius:10px;color:var(--ttk-ink);
  font:500 14px var(--ttk-sans);padding:20px 13px 8px;transition:border-color .2s,box-shadow .2s;
  appearance:none;margin:0}
.ttk-field>textarea{min-height:104px;resize:vertical;line-height:1.55}
.ttk-field>label{position:absolute;left:13px;top:15px;color:var(--ttk-muted);font:500 13.5px var(--ttk-sans);
  pointer-events:none;transform-origin:0 50%;
  transition:transform .24s cubic-bezier(.2,.7,.2,1),color .2s}
.ttk-field>input:focus,.ttk-field>textarea:focus{outline:0;border-color:var(--ttk-accent);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--ttk-accent) 18%,transparent)}
.ttk-field>input:focus+label,.ttk-field>textarea:focus+label,
.ttk-field>input:not(:placeholder-shown)+label,.ttk-field>textarea:not(:placeholder-shown)+label
  {transform:translateY(-9px) scale(.79);color:var(--ttk-accent)}
.ttk-field.ttk-bad>input,.ttk-field.ttk-bad>textarea{border-color:var(--t-red,#f87171)}
.ttk-field.ttk-bad>label{color:var(--t-red,#f87171)}
.ttk-field.ttk-ok>input,.ttk-field.ttk-ok>textarea{border-color:var(--t-green,#4ade80)}
.ttk-hint{display:block;font:400 11.5px var(--ttk-sans);color:var(--ttk-muted);margin:6px 2px 0}
.ttk-hint.ttk-bad{color:var(--t-red,#f87171)}
.ttk-hint.ttk-ok{color:var(--t-green,#4ade80)}

/* ── 21 textarea counter ────────────────────────────────────────────────── */
.ttk-counter{display:flex;justify-content:flex-end;font:400 11px var(--ttk-mono);color:var(--ttk-muted);
  margin-top:5px;gap:2px}
.ttk-counter.ttk-warn{color:var(--t-amber,#fbbf24)}
.ttk-counter.ttk-over{color:var(--t-red,#f87171)}
.ttk-counter b{font-weight:600;color:inherit}

/* ── 22 select (real listbox, not a styled <select>) ───────────────────── */
.ttk-sel{position:relative;display:block}
.ttk-sel-b{width:100%;box-sizing:border-box;display:flex;align-items:center;justify-content:space-between;
  gap:10px;background:var(--ttk-raised);border:1px solid var(--ttk-line);border-radius:10px;
  color:var(--ttk-ink);font:500 14px var(--ttk-sans);padding:12px 13px;cursor:pointer;text-align:left}
.ttk-sel-b:focus-visible{outline:2px solid var(--ttk-accent);outline-offset:2px}
.ttk-sel-b::after{content:"\25BE";color:var(--ttk-accent);font-size:11px;flex:none}
.ttk-sel[data-empty="1"] .ttk-sel-v{color:var(--ttk-muted)}
.ttk-sel-p{position:absolute;top:calc(100% + 6px);left:0;right:0;z-index:70;background:var(--ttk-raised);
  border:1px solid var(--ttk-line);border-radius:var(--ttk-r);padding:6px;box-shadow:var(--ttk-shadow);
  max-height:300px;overflow:auto;transform:scaleY(0);transform-origin:50% 0;opacity:0;visibility:hidden}
.ttk-sel.open .ttk-sel-p{opacity:1;visibility:visible}
.ttk-sel.open .ttk-sel-b{border-color:var(--ttk-accent)}
.ttk-opt{display:flex;align-items:center;gap:9px;width:100%;text-align:left;border:0;background:none;
  color:var(--ttk-muted);font:500 13.5px var(--ttk-sans);padding:9px 11px;border-radius:8px;cursor:pointer}
.ttk-opt:hover,.ttk-opt.ttk-cur{color:var(--ttk-ink);background:color-mix(in srgb,var(--ttk-ink) 7%,transparent)}
.ttk-opt[aria-selected="true"]{color:var(--ttk-accent)}
.ttk-opt[aria-selected="true"]::after{content:"\2713";margin-left:auto;font-size:12px}

/* ── 23 checkbox — the check is drawn, not swapped ──────────────────────── */
.ttk-cb{display:inline-flex;align-items:flex-start;gap:10px;cursor:pointer;user-select:none;
  font:500 13.5px var(--ttk-sans);color:var(--ttk-muted);line-height:1.5}
.ttk-cb input{position:absolute;opacity:0;width:0;height:0}
.ttk-cb-b{position:relative;flex:none;width:20px;height:20px;margin-top:1px;border-radius:6px;
  background:var(--ttk-raised);border:1px solid var(--ttk-line);
  transition:background .2s,border-color .2s,transform .2s cubic-bezier(.34,1.56,.64,1)}
.ttk-cb-b::after{content:"";position:absolute;left:6.5px;top:3px;width:5px;height:9px;
  border:2px solid var(--ttk-on-accent);border-top:0;border-left:0;transform:rotate(42deg) scale(.3);
  opacity:0;transition:transform .26s cubic-bezier(.34,1.56,.64,1),opacity .12s}
.ttk-cb input:checked+.ttk-cb-b{background:var(--ttk-accent);border-color:var(--ttk-accent)}
.ttk-cb input:checked+.ttk-cb-b::after{opacity:1;transform:rotate(42deg) scale(1)}
.ttk-cb:active .ttk-cb-b{transform:scale(.9)}
.ttk-cb input:checked~.ttk-cb-l{color:var(--ttk-ink)}
.ttk-cb input:focus-visible+.ttk-cb-b{outline:2px solid var(--ttk-accent);outline-offset:2px}
.ttk-cb input:disabled+.ttk-cb-b{opacity:.42}
.ttk-cb input:disabled~.ttk-cb-l{opacity:.42;cursor:not-allowed}

/* ── 24 radio — the dot springs in ─────────────────────────────────────── */
.ttk-radio{display:inline-flex;align-items:center;gap:10px;cursor:pointer;user-select:none;
  font:500 13.5px var(--ttk-sans);color:var(--ttk-muted)}
.ttk-radio input{position:absolute;opacity:0;width:0;height:0}
.ttk-radio-b{position:relative;flex:none;width:20px;height:20px;border-radius:50%;background:var(--ttk-raised);
  border:1px solid var(--ttk-line);transition:border-color .2s,background .2s}
.ttk-radio-b::after{content:"";position:absolute;inset:4px;border-radius:50%;background:var(--ttk-accent);
  transform:scale(0);transition:transform .3s cubic-bezier(.34,1.56,.64,1)}
.ttk-radio input:checked+.ttk-radio-b{border-color:var(--ttk-accent);
  background:color-mix(in srgb,var(--ttk-accent) 14%,transparent)}
.ttk-radio input:checked+.ttk-radio-b::after{transform:scale(1)}
.ttk-radio input:checked~.ttk-radio-l{color:var(--ttk-ink)}
.ttk-radio input:focus-visible+.ttk-radio-b{outline:2px solid var(--ttk-accent);outline-offset:2px}
.ttk-radios{display:flex;flex-direction:column;gap:10px}

/* ── 25 segmented control ──────────────────────────────────────────────── */
.ttk-seg{position:relative;display:inline-flex;gap:2px;background:var(--ttk-raised);
  border:1px solid var(--ttk-line);border-radius:11px;padding:4px}
.ttk-seg-ind{position:absolute;left:4px;top:4px;bottom:4px;width:64px;border-radius:8px;
  background:var(--ttk-accent);will-change:transform}
.ttk-seg-i{position:relative;z-index:1;border:0;background:none;color:var(--ttk-muted);
  font:600 13px var(--ttk-sans);padding:8px 14px;border-radius:8px;cursor:pointer;
  transition:color .18s;white-space:nowrap}
.ttk-seg-i.on{color:var(--ttk-on-accent)}
.ttk-seg-i:focus-visible{outline:2px solid var(--ttk-accent);outline-offset:2px}

/* ── 26 range slider ───────────────────────────────────────────────────── */
.ttk-range{-webkit-appearance:none;appearance:none;width:100%;height:26px;background:none;cursor:pointer;
  margin:0}
.ttk-range::-webkit-slider-runnable-track{height:6px;border-radius:99px;
  background:linear-gradient(90deg,var(--ttk-accent) var(--ttk-p,50%),
    var(--ttk-raised) var(--ttk-p,50%));border:1px solid var(--ttk-line)}
.ttk-range::-moz-range-track{height:6px;border-radius:99px;background:var(--ttk-raised);
  border:1px solid var(--ttk-line)}
.ttk-range::-moz-range-progress{height:6px;border-radius:99px;background:var(--ttk-accent)}
.ttk-range::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:20px;height:20px;
  margin-top:-8px;border-radius:50%;background:var(--ttk-ink);border:3px solid var(--ttk-accent);
  transition:transform .2s cubic-bezier(.34,1.56,.64,1),border-radius .2s}
.ttk-range::-moz-range-thumb{width:14px;height:14px;border-radius:50%;background:var(--ttk-ink);
  border:3px solid var(--ttk-accent)}
.ttk-range:active::-webkit-slider-thumb{transform:scale(1.22);border-radius:42%}
.ttk-range:focus-visible{outline:2px solid var(--ttk-accent);outline-offset:4px;border-radius:99px}
.ttk-range-row{display:flex;align-items:center;gap:14px}
.ttk-range-v{font:600 13px var(--ttk-mono);color:var(--ttk-ink);min-width:52px;text-align:right}

/* ── 27 stepper (the accessible ± the commerce set asked for) ──────────── */
.ttk-stepper{display:inline-flex;align-items:center;background:var(--ttk-raised);
  border:1px solid var(--ttk-line);border-radius:10px;overflow:hidden}
.ttk-stepper button{border:0;background:none;color:var(--ttk-muted);font:600 17px var(--ttk-mono);
  width:38px;height:38px;cursor:pointer;transition:color .15s,background .15s}
.ttk-stepper button:hover{color:var(--ttk-ink);background:color-mix(in srgb,var(--ttk-ink) 7%,transparent)}
.ttk-stepper button:focus-visible{outline:2px solid var(--ttk-accent);outline-offset:-2px}
.ttk-stepper button[disabled]{opacity:.3;cursor:default}
.ttk-stepper-w{position:relative;min-width:46px;height:38px;overflow:hidden;
  border-left:1px solid var(--ttk-line);border-right:1px solid var(--ttk-line);
  display:flex;align-items:center;justify-content:center}
.ttk-stepper-v{font:600 14px var(--ttk-mono);color:var(--ttk-ink)}

/* ── 28 file drop ──────────────────────────────────────────────────────── */
.ttk-drop{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:6px;text-align:center;min-height:124px;padding:20px;border-radius:var(--ttk-r);cursor:pointer;
  background:var(--ttk-raised);border:1.5px dashed var(--ttk-line);
  transition:border-color .2s,background .2s,transform .2s cubic-bezier(.34,1.56,.64,1)}
.ttk-drop:hover{border-color:color-mix(in srgb,var(--ttk-accent) 60%,transparent)}
.ttk-drop.ttk-over{border-color:var(--ttk-accent);background:color-mix(in srgb,var(--ttk-accent) 9%,transparent);
  transform:scale(1.01)}
.ttk-drop.ttk-has{border-style:solid;border-color:var(--t-green,#4ade80)}
.ttk-drop input[type=file]{position:absolute;inset:0;opacity:0;cursor:pointer;width:100%;height:100%}
.ttk-drop-i{font-size:22px;line-height:1;color:var(--ttk-accent)}
.ttk-drop-t{font:600 13.5px var(--ttk-sans);color:var(--ttk-ink)}
.ttk-drop-s{font:400 11.5px var(--ttk-sans);color:var(--ttk-muted)}

/* ── 29 submit states — the form-micro-states ask ──────────────────────── */
.ttk-btn{position:relative;display:inline-flex;align-items:center;justify-content:center;gap:9px;
  border:1px solid var(--ttk-line);background:var(--ttk-raised);color:var(--ttk-ink);
  font:600 13.5px var(--ttk-sans);padding:12px 20px;border-radius:10px;cursor:pointer;
  transition:background .18s,border-color .18s,color .18s,transform .12s}
.ttk-btn:hover{border-color:color-mix(in srgb,var(--ttk-accent) 55%,transparent)}
.ttk-btn:active{transform:scale(.975)}
.ttk-btn:focus-visible{outline:2px solid var(--ttk-accent);outline-offset:2px}
.ttk-btn.ttk-primary{background:var(--ttk-accent);border-color:var(--ttk-accent);color:var(--ttk-on-accent)}
.ttk-btn[disabled],.ttk-btn[aria-busy="true"]{opacity:.68;cursor:progress}
.ttk-btn[aria-busy="true"] .ttk-btn-l{opacity:.55}
.ttk-btn.ttk-good{background:var(--t-green,#4ade80);border-color:var(--t-green,#4ade80);
  color:#0b2118;animation:ttkPop .26s cubic-bezier(.2,.7,.3,1.4)}
.ttk-btn.ttk-bad{background:var(--t-red,#f87171);border-color:var(--t-red,#f87171);
  color:#2a0b0b;animation:ttkPop .26s cubic-bezier(.2,.7,.3,1.4)}
@keyframes ttkPop{from{transform:scale(.94)}}
.ttk-btn .ttk-spin{display:none}
.ttk-btn[aria-busy="true"] .ttk-spin{display:block}

/* ── 30 modal ──────────────────────────────────────────────────────────── */
.ttk-modal{position:fixed;inset:0;z-index:3000;display:none;align-items:center;justify-content:center;
  padding:20px}
.ttk-modal.ttk-open{display:flex}
.ttk-modal-veil{position:absolute;inset:0;background:rgba(8,5,16,.62);backdrop-filter:blur(5px);
  opacity:0;transition:opacity .25s}
.ttk-modal.ttk-in .ttk-modal-veil{opacity:1}
.ttk-modal-p{position:relative;width:min(520px,100%);max-height:86vh;overflow:auto;
  background:var(--ttk-surface);border:1px solid var(--ttk-line);border-radius:var(--ttk-r);
  box-shadow:var(--ttk-shadow);padding:22px;transform:scale(.92);opacity:0;will-change:transform;
  transition:transform .34s cubic-bezier(.34,1.4,.64,1),opacity .22s}
.ttk-modal.ttk-in .ttk-modal-p{transform:none;opacity:1}
.ttk-modal-h{font:650 17px var(--ttk-sans);color:var(--ttk-ink);margin:0 0 6px}
.ttk-modal-b{font:400 13.5px/1.6 var(--ttk-sans);color:var(--ttk-muted);margin:0}
.ttk-modal-f{display:flex;justify-content:flex-end;gap:9px;margin-top:20px}
.ttk-modal-x{position:absolute;top:12px;right:12px;border:0;background:none;color:var(--ttk-muted);
  font:400 19px/1 var(--ttk-mono);cursor:pointer;padding:5px 8px;border-radius:8px}
.ttk-modal-x:hover{color:var(--ttk-ink)}
/* --ttk-sbw is set by the kit at lock time to the width of the scrollbar it
   just hid, so the page does not lurch sideways when the lock takes effect */
html.ttk-lock{overflow:hidden;padding-right:var(--ttk-sbw,0px)}
html.ttk-lock body{overflow:hidden}

/* ── 31 drawer ─────────────────────────────────────────────────────────── */
.ttk-drawer{position:fixed;inset:0;z-index:3000;display:none}
.ttk-drawer.ttk-open{display:block}
.ttk-drawer-veil{position:absolute;inset:0;background:rgba(8,5,16,.55);backdrop-filter:blur(4px);
  opacity:0;transition:opacity .28s}
.ttk-drawer.ttk-in .ttk-drawer-veil{opacity:1}
.ttk-drawer-p{position:absolute;top:0;bottom:0;right:0;width:min(420px,92vw);
  background:var(--ttk-surface);border-left:1px solid var(--ttk-line);box-shadow:var(--ttk-shadow);
  padding:22px;overflow:auto;transform:translateX(100%);will-change:transform;
  transition:transform .38s cubic-bezier(.2,.85,.25,1)}
/* the side rule MUST come before the open rule: both are (0,3,0), so with the
   open rule first the attribute selector won the tie and a data-side="left"
   drawer could never leave translateX(-100%) — it opened its veil over an
   empty page. Order is the fix; do not "tidy" these two apart. */
.ttk-drawer[data-side="left"] .ttk-drawer-p{right:auto;left:0;border-left:0;
  border-right:1px solid var(--ttk-line);transform:translateX(-100%)}
.ttk-drawer.ttk-in .ttk-drawer-p{transform:none}
.ttk-drawer-h{font:650 16px var(--ttk-sans);color:var(--ttk-ink);margin:0 0 14px}

/* ── 32 tooltip — pure CSS, hover and focus ────────────────────────────── */
.ttk-tip{position:relative;border-bottom:1px dotted var(--ttk-muted);cursor:help}
.ttk-tip::after{content:attr(data-tip);position:absolute;bottom:calc(100% + 9px);left:50%;
  transform:translate(-50%,4px) scale(.94);transform-origin:50% 100%;
  background:var(--ttk-ink);color:var(--ttk-bg);font:500 11.5px/1.4 var(--ttk-sans);
  padding:6px 10px;border-radius:8px;white-space:nowrap;pointer-events:none;
  opacity:0;transition:opacity .16s,transform .22s cubic-bezier(.34,1.56,.64,1);z-index:80}
.ttk-tip::before{content:"";position:absolute;bottom:calc(100% + 3px);left:50%;margin-left:-5px;
  border:5px solid transparent;border-top-color:var(--ttk-ink);opacity:0;transition:opacity .16s;
  pointer-events:none;z-index:80}
.ttk-tip:hover::after,.ttk-tip:focus-visible::after,.ttk-tip:hover::before,.ttk-tip:focus-visible::before
  {opacity:1}
.ttk-tip:hover::after,.ttk-tip:focus-visible::after{transform:translate(-50%,0) scale(1)}
.ttk-tip[data-tip-pos="bottom"]::after{bottom:auto;top:calc(100% + 9px);transform-origin:50% 0;
  transform:translate(-50%,-4px) scale(.94)}
.ttk-tip[data-tip-pos="bottom"]::before{bottom:auto;top:calc(100% + 3px);border-top-color:transparent;
  border-bottom-color:var(--ttk-ink)}
.ttk-tip[data-tip-pos="bottom"]:hover::after,.ttk-tip[data-tip-pos="bottom"]:focus-visible::after
  {transform:translate(-50%,0) scale(1)}

/* ── 33 command palette ────────────────────────────────────────────────── */
.ttk-cmd{position:fixed;inset:0;z-index:3200;display:none;padding:12vh 20px 20px;justify-content:center}
.ttk-cmd.ttk-open{display:flex}
.ttk-cmd-veil{position:absolute;inset:0;background:rgba(8,5,16,.6);backdrop-filter:blur(6px);
  opacity:0;transition:opacity .2s}
.ttk-cmd.ttk-in .ttk-cmd-veil{opacity:1}
.ttk-cmd-b{position:relative;width:min(560px,100%);height:fit-content;max-height:66vh;display:flex;
  flex-direction:column;background:var(--ttk-surface);border:1px solid var(--ttk-line);
  border-radius:var(--ttk-r);box-shadow:var(--ttk-shadow);overflow:hidden;opacity:0;
  transform:translateY(-10px) scale(.97);will-change:transform;
  transition:transform .3s cubic-bezier(.34,1.4,.64,1),opacity .2s}
.ttk-cmd.ttk-in .ttk-cmd-b{transform:none;opacity:1}
.ttk-cmd-i{width:100%;box-sizing:border-box;border:0;border-bottom:1px solid var(--ttk-line);
  background:none;color:var(--ttk-ink);font:500 15px var(--ttk-sans);padding:16px 18px}
.ttk-cmd-i:focus{outline:0}
.ttk-cmd-i::placeholder{color:var(--ttk-muted)}
.ttk-cmd-l{overflow:auto;padding:6px;position:relative}
/* position:relative is load-bearing: scrollRowInto() positions the highlight
   from row.offsetTop, which is measured against the nearest POSITIONED
   ancestor — without this the offsets belong to .ttk-cmd-b and the list
   scrolled to the wrong place whenever it overflowed. */
.ttk-cmd-g{font:600 10px var(--ttk-mono);color:var(--ttk-muted);text-transform:uppercase;
  letter-spacing:.12em;padding:10px 12px 5px}
.ttk-cmd-o{display:flex;align-items:center;gap:11px;width:100%;text-align:left;border:0;background:none;
  color:var(--ttk-muted);font:500 13.5px var(--ttk-sans);padding:10px 12px;border-radius:9px;cursor:pointer;
  text-decoration:none}
.ttk-cmd-o .ttk-cmd-k{margin-left:auto;font:500 10.5px var(--ttk-mono);color:var(--ttk-muted);
  border:1px solid var(--ttk-line);border-radius:6px;padding:2px 6px}
.ttk-cmd-o.ttk-cur{background:color-mix(in srgb,var(--ttk-accent) 15%,transparent);color:var(--ttk-ink)}
.ttk-cmd-o:hover{color:var(--ttk-ink)}
.ttk-cmd-e{padding:26px 18px;text-align:center;font:400 13px var(--ttk-sans);color:var(--ttk-muted)}
.ttk-kbd{font:500 10.5px var(--ttk-mono);border:1px solid var(--ttk-line);border-bottom-width:2px;
  border-radius:6px;padding:2px 6px;color:var(--ttk-muted)}

/* ── 34 popover ────────────────────────────────────────────────────────── */
.ttk-pop{position:relative;display:inline-block}
.ttk-pop-p{position:absolute;top:calc(100% + 8px);left:0;z-index:70;min-width:240px;
  background:var(--ttk-surface);border:1px solid var(--ttk-line);border-radius:var(--ttk-r);
  box-shadow:var(--ttk-shadow);padding:14px;opacity:0;visibility:hidden;transform:translateY(-6px) scale(.97);
  transform-origin:0 0;transition:opacity .18s,transform .24s cubic-bezier(.34,1.56,.64,1),visibility .18s}
.ttk-pop.open .ttk-pop-p{opacity:1;visibility:visible;transform:none}
.ttk-pop[data-pos="right"] .ttk-pop-p{top:0;left:calc(100% + 8px);transform-origin:0 0}
.ttk-pop[data-pos="up"] .ttk-pop-p{top:auto;bottom:calc(100% + 8px);transform-origin:0 100%}

/* ── 35 alerts / banners ───────────────────────────────────────────────── */
.ttk-alert{position:relative;display:flex;gap:11px;align-items:flex-start;overflow:hidden;
  background:var(--ttk-raised);border:1px solid var(--ttk-line);border-left-width:3px;
  border-radius:10px;padding:12px 40px 12px 14px;margin:0 0 10px;
  font:400 13px/1.6 var(--ttk-sans);color:var(--ttk-muted)}
.ttk-alert b{color:var(--ttk-ink);font-weight:600}
.ttk-alert-i{flex:none;font:600 13px var(--ttk-mono);line-height:1.5}
.ttk-alert-x{position:absolute;top:8px;right:8px;border:0;background:none;color:var(--ttk-muted);
  font:400 15px/1 var(--ttk-mono);cursor:pointer;padding:4px 6px;border-radius:7px}
.ttk-alert-x:hover{color:var(--ttk-ink);background:color-mix(in srgb,var(--ttk-ink) 8%,transparent)}
.ttk-alert.ttk-ok{--a:var(--t-green,#4ade80);border-left-color:var(--a)}
.ttk-alert.ttk-ok .ttk-alert-i{color:var(--a)}
.ttk-alert.ttk-info{--a:var(--ttk-accent);border-left-color:var(--a)}
.ttk-alert.ttk-info .ttk-alert-i{color:var(--a)}
.ttk-alert.ttk-warn{--a:var(--t-amber,#fbbf24);border-left-color:var(--a)}
.ttk-alert.ttk-warn .ttk-alert-i{color:var(--a)}
.ttk-alert.ttk-err{--a:var(--t-red,#f87171);border-left-color:var(--a)}
.ttk-alert.ttk-err .ttk-alert-i{color:var(--a)}
/* dismissal collapses the box; JS measures the height into --ttk-h first */
.ttk-alert.ttk-closing{transition:height .3s cubic-bezier(.2,.7,.2,1),opacity .25s,margin .3s,padding .3s;
  height:var(--ttk-h)}
.ttk-alert.ttk-gone{height:0;opacity:0;margin-bottom:0;padding-top:0;padding-bottom:0;border-width:0}

/* ── 36 skeleton — the honest placeholder ──────────────────────────────── */
.ttk-skel{position:relative;overflow:hidden;background:var(--ttk-raised);border-radius:7px;
  height:var(--h,13px);width:var(--w,100%);margin:0 0 var(--gap,9px)}
.ttk-skel::after{content:"";position:absolute;inset:0;
  background:linear-gradient(90deg,transparent,color-mix(in srgb,var(--ttk-ink) 9%,transparent),transparent);
  transform:translateX(-100%);animation:ttkShim 1.5s infinite}
@keyframes ttkShim{to{transform:translateX(100%)}}
.ttk-skel.ttk-skel-c{height:96px;border-radius:var(--ttk-r);--gap:14px}
.ttk-skel.ttk-skel-t{height:22px;width:46%;--gap:11px}

/* ── 37 progress ───────────────────────────────────────────────────────── */
.ttk-prog{position:relative;overflow:hidden;height:8px;border-radius:99px;background:var(--ttk-raised);
  border:1px solid var(--ttk-line);width:100%}
.ttk-prog-f{height:100%;width:var(--ttk-v,0%);border-radius:99px;background:var(--ttk-accent);
  will-change:width}
/* without JS there is no spring, so the bar still animates as a state change */
html:not(.ttk-js) .ttk-prog-f{transition:width .55s cubic-bezier(.2,.7,.2,1)}
.ttk-prog.ttk-indet .ttk-prog-f{width:34%;animation:ttkIndet 1.3s cubic-bezier(.6,.05,.4,.95) infinite}
@keyframes ttkIndet{0%{transform:translateX(-100%)}100%{transform:translateX(330%)}}
.ttk-prog.ttk-prog-lg{height:12px}
.ttk-prog-row{display:flex;align-items:center;gap:12px}
.ttk-prog-v{font:600 12px var(--ttk-mono);color:var(--ttk-ink);min-width:44px;text-align:right}

/* ── 38 spinner ────────────────────────────────────────────────────────── */
.ttk-spin{--s:18px;width:var(--s);height:var(--s);flex:none;animation:ttkSpinRot .95s linear infinite}
.ttk-spin circle{fill:none;stroke:var(--ttk-accent);stroke-width:2.5;stroke-linecap:round;
  stroke-dasharray:42;stroke-dashoffset:30;animation:ttkSpinDash 1.7s ease-in-out infinite}
@keyframes ttkSpinRot{to{transform:rotate(360deg)}}
@keyframes ttkSpinDash{0%{stroke-dashoffset:40}50%{stroke-dashoffset:10}100%{stroke-dashoffset:40}}
.ttk-spin.ttk-spin-lg{--s:30px}
.ttk-spin.ttk-spin-sm{--s:13px}
.ttk-spin-row{display:inline-flex;align-items:center;gap:9px;font:500 12.5px var(--ttk-sans);
  color:var(--ttk-muted)}

/* ── 39 empty state ────────────────────────────────────────────────────── */
.ttk-empty{display:flex;flex-direction:column;align-items:center;text-align:center;gap:7px;
  padding:34px 20px;border:1px dashed var(--ttk-line);border-radius:var(--ttk-r);
  background:color-mix(in srgb,var(--ttk-raised) 55%,transparent)}
.ttk-empty-i{font-size:26px;line-height:1;color:var(--ttk-accent);opacity:.9}
.ttk-empty-t{font:600 14.5px var(--ttk-sans);color:var(--ttk-ink)}
.ttk-empty-b{font:400 12.5px/1.6 var(--ttk-sans);color:var(--ttk-muted);max-width:44ch}
.ttk-empty .ttk-btn{margin-top:8px}

/* ── 40 badge + status dot ─────────────────────────────────────────────── */
.ttk-badge{display:inline-flex;align-items:center;gap:6px;font:600 10.5px var(--ttk-sans);
  letter-spacing:.04em;text-transform:uppercase;padding:4px 9px;border-radius:99px;
  background:color-mix(in srgb,var(--ttk-ink) 8%,transparent);color:var(--ttk-muted);
  border:1px solid transparent}
.ttk-badge.ttk-ok{background:color-mix(in srgb,var(--t-green,#4ade80) 15%,transparent);
  color:var(--t-green,#4ade80)}
.ttk-badge.ttk-info{background:color-mix(in srgb,var(--ttk-accent) 16%,transparent);
  color:var(--ttk-accent)}
.ttk-badge.ttk-warn{background:color-mix(in srgb,var(--t-amber,#fbbf24) 16%,transparent);
  color:var(--t-amber,#fbbf24)}
.ttk-badge.ttk-err{background:color-mix(in srgb,var(--t-red,#f87171) 16%,transparent);
  color:var(--t-red,#f87171)}
.ttk-badge.ttk-outline{background:none;border-color:var(--ttk-line);color:var(--ttk-muted)}
.ttk-dot{position:relative;display:inline-block;width:9px;height:9px;border-radius:50%;
  background:var(--ttk-muted);flex:none}
.ttk-dot.ttk-ok{background:var(--t-green,#4ade80)}
.ttk-dot.ttk-warn{background:var(--t-amber,#fbbf24)}
.ttk-dot.ttk-err{background:var(--t-red,#f87171)}
.ttk-dot.ttk-info{background:var(--ttk-accent)}
/* the live pulse: a ring that expands and fades */
.ttk-dot.ttk-live::after{content:"";position:absolute;inset:0;border-radius:50%;
  border:1.5px solid var(--t-green,#4ade80);animation:ttkPulse 2.4s ease-out infinite}
.ttk-dot.ttk-err.ttk-live::after{border-color:var(--t-red,#f87171)}
.ttk-dot.ttk-warn.ttk-live::after{border-color:var(--t-amber,#fbbf24)}
.ttk-dot.ttk-info.ttk-live::after{border-color:var(--ttk-accent)}
@keyframes ttkPulse{0%{transform:scale(1);opacity:.7}70%,100%{transform:scale(2.6);opacity:0}}

/* ── 41 avatar stack ───────────────────────────────────────────────────── */
.ttk-avs{display:inline-flex;align-items:center}
.ttk-av{display:flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:50%;
  background:var(--ttk-raised);border:2px solid var(--ttk-bg);color:var(--ttk-ink);
  font:600 11.5px var(--ttk-sans);overflow:hidden;flex:none;
  transition:transform .32s cubic-bezier(.34,1.56,.64,1)}
.ttk-av+.ttk-av{margin-left:-10px}
.ttk-av img{width:100%;height:100%;object-fit:cover}
.ttk-avs:hover .ttk-av{transform:translateX(calc(var(--i,0) * 6px))}
.ttk-av.ttk-av-more{background:color-mix(in srgb,var(--ttk-accent) 22%,transparent);
  color:var(--ttk-accent);font-size:10.5px}

/* ── 42 stat card + sparkline ──────────────────────────────────────────── */
.ttk-stat{background:var(--ttk-raised);border:1px solid var(--ttk-line);border-radius:var(--ttk-r);
  padding:16px;display:flex;flex-direction:column;gap:4px;position:relative;overflow:hidden}
.ttk-stat-k{font:500 10.5px var(--ttk-mono);color:var(--ttk-muted);text-transform:uppercase;
  letter-spacing:.11em}
.ttk-stat-v{font:700 26px var(--ttk-mono);color:var(--ttk-ink);letter-spacing:-.01em;line-height:1.15}
.ttk-stat-d{display:inline-flex;align-items:center;gap:5px;font:600 11.5px var(--ttk-sans)}
.ttk-stat-d.ttk-up{color:var(--t-green,#4ade80)}
.ttk-stat-d.ttk-down{color:var(--t-red,#f87171)}
.ttk-spark{display:block;width:100%;height:38px;margin-top:4px;overflow:visible}
.ttk-spark path{fill:none;stroke:var(--ttk-accent);stroke-width:2;stroke-linecap:round;
  stroke-linejoin:round}
.ttk-spark .ttk-spark-a{fill:color-mix(in srgb,var(--ttk-accent) 14%,transparent);stroke:none;
  opacity:0;transition:opacity .6s .45s}
.ttk-spark .ttk-spark-l{stroke-dasharray:var(--ttk-len,400);stroke-dashoffset:var(--ttk-len,400);
  transition:stroke-dashoffset 1.2s cubic-bezier(.2,.7,.2,1)}
.ttk-in .ttk-spark .ttk-spark-l{stroke-dashoffset:0}
.ttk-in .ttk-spark .ttk-spark-a{opacity:1}

/* ── 43 timeline (the repair-status shape) ─────────────────────────────── */
.ttk-tl{position:relative;display:flex;flex-direction:column;padding-left:22px}
.ttk-tl::before{content:"";position:absolute;left:5px;top:6px;bottom:6px;width:1.5px;
  background:var(--ttk-line)}
.ttk-tl-i{position:relative;padding:0 0 18px 0}
.ttk-tl-i:last-child{padding-bottom:0}
.ttk-tl-i::before{content:"";position:absolute;left:-22px;top:4px;width:11px;height:11px;border-radius:50%;
  background:var(--ttk-raised);border:1.5px solid var(--ttk-line);
  transition:background .35s,border-color .35s,transform .4s cubic-bezier(.34,1.56,.64,1)}
.ttk-tl-i.ttk-on::before{background:var(--ttk-accent);border-color:var(--ttk-accent);transform:scale(1.18)}
.ttk-tl-t{font:600 13px var(--ttk-sans);color:var(--ttk-muted);transition:color .3s}
.ttk-tl-i.ttk-on .ttk-tl-t{color:var(--ttk-ink)}
.ttk-tl-s{font:400 11.5px var(--ttk-sans);color:var(--ttk-muted);margin-top:2px}
.ttk-tl-w{font:400 10.5px var(--ttk-mono);color:var(--ttk-accent);margin-top:3px}

/* ── 44 meter rows ─────────────────────────────────────────────────────── */
.ttk-meters{display:flex;flex-direction:column;gap:13px}
.ttk-meter{display:grid;grid-template-columns:1fr auto;gap:4px 10px}
.ttk-meter-l{font:500 12.5px var(--ttk-sans);color:var(--ttk-muted)}
.ttk-meter-v{font:600 12px var(--ttk-mono);color:var(--ttk-ink)}
.ttk-meter-t{grid-column:1/-1;height:6px;border-radius:99px;background:var(--ttk-raised);
  border:1px solid var(--ttk-line);overflow:hidden}
.ttk-meter-f{height:100%;width:var(--ttk-v,0%);background:var(--ttk-accent);border-radius:99px;
  will-change:width}

/* ── 45 breadcrumbs ────────────────────────────────────────────────────── */
.ttk-crumbs{display:flex;align-items:center;gap:8px;flex-wrap:wrap;font:500 12.5px var(--ttk-sans)}
.ttk-crumbs a{color:var(--ttk-muted);text-decoration:none;transition:color .15s}
.ttk-crumbs a:hover{color:var(--ttk-ink)}
.ttk-crumbs .ttk-crumb-s{color:var(--ttk-line);font-family:var(--ttk-mono);font-size:11px}
.ttk-crumbs [aria-current="page"]{color:var(--ttk-ink);font-weight:600}

/* ── 46 steps ──────────────────────────────────────────────────────────── */
.ttk-steps{display:flex;align-items:flex-start;width:100%}
.ttk-stp{position:relative;flex:1;display:flex;flex-direction:column;align-items:center;gap:7px;
  text-align:center;min-width:0}
.ttk-stp::before{content:"";position:absolute;top:13px;left:0;right:50%;height:1.5px;
  background:var(--ttk-line)}
.ttk-stp::after{content:"";position:absolute;top:13px;left:50%;right:0;height:1.5px;
  background:var(--ttk-line)}
.ttk-stp:first-child::before,.ttk-stp:last-child::after{background:none}
.ttk-stp-n{position:relative;z-index:1;width:27px;height:27px;border-radius:50%;display:flex;
  align-items:center;justify-content:center;background:var(--ttk-surface);border:1.5px solid var(--ttk-line);
  font:600 11.5px var(--ttk-mono);color:var(--ttk-muted);
  transition:background .3s,border-color .3s,color .3s,transform .35s cubic-bezier(.34,1.56,.64,1)}
.ttk-stp-l{font:500 11.5px/1.4 var(--ttk-sans);color:var(--ttk-muted);max-width:12ch;
  transition:color .3s}
.ttk-stp[data-st="done"] .ttk-stp-n{background:var(--ttk-accent);border-color:var(--ttk-accent);
  color:var(--ttk-on-accent)}
.ttk-stp[data-st="done"] .ttk-stp-l{color:var(--ttk-ink)}
.ttk-stp[data-st="done"]::before,.ttk-stp[data-st="done"]::after{background:var(--ttk-accent)}
.ttk-stp[data-st="now"] .ttk-stp-n{border-color:var(--ttk-accent);color:var(--ttk-accent);
  transform:scale(1.12)}
.ttk-stp[data-st="now"] .ttk-stp-l{color:var(--ttk-ink);font-weight:600}
.ttk-stp[data-st="now"]::before{background:var(--ttk-accent)}

/* ── 47 rating ─────────────────────────────────────────────────────────── */
.ttk-rate{display:inline-flex;align-items:center;gap:3px}
.ttk-rate-s{border:0;background:none;padding:1px;cursor:default;line-height:1;color:var(--ttk-line);
  font-size:17px;transition:color .18s,transform .24s cubic-bezier(.34,1.56,.64,1)}
.ttk-rate-s.ttk-on{color:var(--t-amber,#fbbf24)}
.ttk-rate.ttk-set .ttk-rate-s{cursor:pointer}
.ttk-rate.ttk-set .ttk-rate-s:hover{transform:scale(1.22)}
.ttk-rate-n{font:600 12px var(--ttk-mono);color:var(--ttk-muted);margin-left:5px}
.ttk-rate-big .ttk-rate-s{font-size:24px}

/* a flashed element the toast has already taken over */
html.ttk-js .ttk-flash-done{display:none}

/* ── hook-only classes — no styles by design ───────────────────────────── */
/* These exist so the JS has a stable place to look. An audit that flags them
   as "undefined in CSS" is reading them wrong: they are contracts, and the
   element wearing them is styled by a real component class next to it.
     .ttk-dd-label   — the span inside .ttk-dd-btn whose text the dropdown swaps
     .ttk-fieldwrap  — wraps .ttk-field + .ttk-counter so the counter can find it
     .ttk-pop-b      — the popover's trigger (style it as .ttk-btn)
     .ttk-btn-l      — the button label span; TTK.btn() writes here, never into
                       the button, so swapping text cannot eat the spinner
     .ttk-cur        — the keyboard-highlighted row in a listbox / palette      */

/* ── reduced motion: every component lands in its final state ───────────── */@media (prefers-reduced-motion: reduce){
  .ttk-wave .ttk-l{transition:none} .ttk-wave:hover .ttk-l{transform:none}
  .ttk-dd-i{transition:none} .ttk-dd-menu{transition:none}
  .ttk-mq-t{animation:none} .ttk-toast{transition:none}
  .ttk-toast-bar{animation:none;transform:scaleX(0)}
  .ttk-tgl-k{transition:none} html.ttk-js .ttk-rv{opacity:1;transform:none}
  .ttk-panel.on{animation:none} .ttk-tilt{transition:none} .ttk-tilt::after{display:none}
  .ttk-jelly-blob{transition:none}
  /* batch 3 — same rule: land in the final state, keep the meaning */
  .ttk-mo-d{animation:none;left:calc(100% - 23px)}
  .ttk-skel::after{animation:none;opacity:.35;transform:none}
  .ttk-spin{animation:none} .ttk-spin circle{animation:none;stroke-dashoffset:12}
  .ttk-prog.ttk-indet .ttk-prog-f{animation:none;width:100%;opacity:.45}
  .ttk-dot.ttk-live::after{animation:none;opacity:0}
  .ttk-avs:hover .ttk-av{transform:none}
  .ttk-spark .ttk-spark-l{transition:none;stroke-dashoffset:0}
  .ttk-spark .ttk-spark-a{transition:none;opacity:1}
  .ttk-cb-b::after{transition:none} .ttk-cb:active .ttk-cb-b{transform:none}
  .ttk-radio-b::after{transition:none}
  .ttk-tip::after{transition:none} .ttk-btn.ttk-good,.ttk-btn.ttk-bad{animation:none}
  .ttk-alert.ttk-closing{transition:none}
  /* 2.0.1 — overlays and the controls that move on press were still animating
     under reduced motion: the JS half was instant but the CSS transitions ran
     their full duration regardless. Land everything. */
  .ttk-modal-veil,.ttk-modal-p,.ttk-drawer-veil,.ttk-drawer-p,
  .ttk-cmd-veil,.ttk-cmd-b,.ttk-pop-p,.ttk-tip::before,
  .ttk-drop,.ttk-stp-n,.ttk-tl-i::before,.ttk-av,.ttk-badge{transition:none}
  .ttk-range:active::-webkit-slider-thumb{transform:none}
  .ttk-rate.ttk-set .ttk-rate-s:hover{transform:none}
}

/* ── v2.1.0 — BATCH 4: the commerce set (2026-09-27) ──────────────────────
   48 product card · 49 gallery thumbs · 50 order summary · 51 review ·
   52 newsletter block · + .ttk-sr (screen-reader only utility).
   48/50/51/52 are markup+CSS patterns (no JS, like the badge). 49 gets a
   small JS behavior: roving tabindex + arrow keys on the thumb rail, and a
   bubbling `ttk:galview` event the host uses to swap the main image.
   Painted from --ttk-* tokens only, so hosts re-skin via the theme bridge. */
.ttk-prodcard{position:relative;display:flex;flex-direction:column;background:var(--ttk-raised);
  border:1px solid var(--ttk-line);border-radius:12px;overflow:hidden;color:var(--ttk-ink);
  text-decoration:none;transition:transform .26s cubic-bezier(.2,.7,.3,1.2),box-shadow .26s ease}
.ttk-prodcard:hover{transform:translateY(-3px);box-shadow:var(--ttk-shadow)}
.ttk-prodcard:focus-visible{outline:2px solid var(--ttk-accent);outline-offset:2px}
.ttk-prodcard-art{background:var(--ttk-surface);border-bottom:1px solid var(--ttk-line);
  aspect-ratio:4/3;display:grid;place-items:center;padding:12px}
.ttk-prodcard-art svg{width:100%;height:100%}
.ttk-prodcard-body{display:flex;flex-direction:column;gap:5px;padding:13px 15px 15px;flex:1}
.ttk-prodcard-brand{font-size:.75rem;letter-spacing:.1em;text-transform:uppercase;color:var(--ttk-muted);font-weight:700}
.ttk-prodcard-model{font-weight:650;letter-spacing:-.01em;font-size:1.06rem}
.ttk-prodcard-cond{font-size:.82rem;color:var(--ttk-muted)}
.ttk-prodcard-price{margin-top:auto;font-weight:700;display:flex;gap:9px;align-items:baseline}
.ttk-prodcard-price del{color:var(--ttk-muted);font-weight:400;font-size:.88rem}
.ttk-prodcard.ttk-sold{opacity:.72}
.ttk-prodcard .ttk-badge{align-self:flex-start}
.ttk-gal-t{cursor:pointer;background:var(--ttk-surface);border:1px solid var(--ttk-line);
  border-radius:8px;padding:5px;opacity:.7;display:block}
.ttk-gal-t[aria-selected="true"]{border-color:var(--ttk-accent);opacity:1}
.ttk-gal-t:focus-visible{outline:2px solid var(--ttk-accent);outline-offset:2px}
.ttk-gal-t svg{width:100%;height:auto;display:block}
.ttk-osum table{width:100%;border-collapse:collapse;font-size:.95rem}
.ttk-osum th{text-align:left;color:var(--ttk-muted);font-weight:400;padding:8px 4px}
.ttk-osum td{text-align:right;font-weight:700;padding:8px 4px}
.ttk-osum tr{border-bottom:1px solid var(--ttk-line)}
.ttk-osum tr:last-child{border-bottom:0}
.ttk-review{margin:0;background:var(--ttk-raised);border:1px solid var(--ttk-line);border-radius:12px;padding:14px 16px}
.ttk-review blockquote{margin:0}
.ttk-review blockquote p{margin:6px 0 0}
.ttk-review .ttk-review-meta{display:flex;gap:10px;align-items:center;flex-wrap:wrap;font-size:.85rem;color:var(--ttk-muted);margin-top:8px}
.ttk-news{display:grid;grid-template-columns:1.2fr 1fr;gap:24px;align-items:center;
  background:var(--ttk-raised);border:1px solid var(--ttk-line);border-radius:16px;padding:26px 30px}
.ttk-news h2{margin:0 0 6px;letter-spacing:-.014em}
.ttk-news p{margin:0;color:var(--ttk-muted)}
@media (max-width:720px){.ttk-news{grid-template-columns:1fr}}
.ttk-sr{position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;
  clip:rect(0 0 0 0);clip-path:inset(50%);overflow:hidden;white-space:nowrap}
