/* ==========================================================================
   Unfiled — app mockup components
   Hand-drawn macOS window chrome used in place of screenshots. Labels, status
   strings and severity colors mirror what the app actually renders.
   Windows follow the page theme by default so they sit naturally in the page;
   add .win--light or .win--dark to pin one appearance for a comparison.
   ========================================================================== */

/* A window mockup has a real minimum width — a tab strip and an action bar
   cannot usefully compress. Below that width the frame scrolls on its own so
   the page body never does. */
.frame { display: grid; gap: 12px; }
@media (max-width: 720px) {
  .frame {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    /* room for the window's shadow, which would otherwise be clipped */
    padding: 6px 6px 10px;
    margin: -6px -6px -10px;
  }
  .frame > .win { min-width: 560px; }
  .frame__caption { position: sticky; left: 0; }
}
.frame__caption { font-size: 13px; color: var(--faint); }

.win {
  --w-chrome: #f6f5f4;
  --w-edge: #d8d8db;
  --w-canvas: #ffffff;
  --w-bar: #f6f5f4;
  --w-tab: #e8e7e6;
  --w-tab-live: #ffffff;
  --w-fg: #1d1d1f;
  --w-fg2: #6e6e73;
  --w-fg3: #aeaeb2;
  --w-btn: #ffffff;
  --w-btn-edge: rgba(0, 0, 0, .12);
  --w-hover: rgba(0, 0, 0, .06);
  --w-accent-soft: #e9f1fc;
  --w-accent: #0a57b4;
  --w-gutter: #e3e3e6;
  --w-sel: rgba(10, 132, 255, .14);

  position: relative;
  border-radius: 11px;
  overflow: hidden;
  background: var(--w-canvas);
  color: var(--w-fg);
  font-size: 13px;
  line-height: 1.45;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .13), var(--shadow-lg);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .win:not(.win--light) {
    --w-chrome: #323234; --w-edge: #0b0b0c; --w-canvas: #1e1e1e;
    --w-bar: #2b2b2e; --w-tab: #2a2a2d; --w-tab-live: #1e1e1e;
    --w-fg: #f5f5f7; --w-fg2: #a1a1a6; --w-fg3: #636366;
    --w-btn: #3a3a3d; --w-btn-edge: rgba(255, 255, 255, .14);
    --w-hover: rgba(255, 255, 255, .08);
    --w-accent-soft: #1b3556; --w-accent: #7fb7ff;
    --w-gutter: #2f2f32; --w-sel: rgba(10, 132, 255, .22);
    box-shadow: 0 0 0 1px rgba(255, 255, 255, .1), var(--shadow-lg);
  }
}

/* The same, chosen explicitly rather than inherited from the system.
   A media query cannot express "Dark on a light Mac". */
:root[data-theme="dark"] .win:not(.win--light) {
    --w-chrome: #323234; --w-edge: #0b0b0c; --w-canvas: #1e1e1e;
    --w-bar: #2b2b2e; --w-tab: #2a2a2d; --w-tab-live: #1e1e1e;
    --w-fg: #f5f5f7; --w-fg2: #a1a1a6; --w-fg3: #636366;
    --w-btn: #3a3a3d; --w-btn-edge: rgba(255, 255, 255, .14);
    --w-hover: rgba(255, 255, 255, .08);
    --w-accent-soft: #1b3556; --w-accent: #7fb7ff;
    --w-gutter: #2f2f32; --w-sel: rgba(10, 132, 255, .22);
    box-shadow: 0 0 0 1px rgba(255, 255, 255, .1), var(--shadow-lg);
  }

.win--dark {
  --w-chrome: #323234; --w-edge: #0b0b0c; --w-canvas: #1e1e1e;
  --w-bar: #2b2b2e; --w-tab: #2a2a2d; --w-tab-live: #1e1e1e;
  --w-fg: #f5f5f7; --w-fg2: #a1a1a6; --w-fg3: #636366;
  --w-btn: #3a3a3d; --w-btn-edge: rgba(255, 255, 255, .14);
  --w-hover: rgba(255, 255, 255, .08);
  --w-accent-soft: #1b3556; --w-accent: #7fb7ff;
  --w-gutter: #2f2f32; --w-sel: rgba(10, 132, 255, .22);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .1), var(--shadow-lg);
}

/* ---------- title bar ---------- */
.win__titlebar {
  height: 48px;
  background: var(--w-chrome);
  border-bottom: 1px solid var(--w-edge);
  display: grid;
  grid-template-columns: auto auto 1fr auto;
  align-items: center;
  gap: 14px;
  padding: 0 12px 0 13px;
}
.lights { display: flex; gap: 8px; }
.lights i {
  width: 11px; height: 11px; border-radius: 50%;
  box-shadow: inset 0 0 0 .5px rgba(0, 0, 0, .16);
}
.lights i:nth-child(1) { background: #ff5f57; }
.lights i:nth-child(2) { background: #febc2e; }
.lights i:nth-child(3) { background: #28c840; }
.win__title { font-weight: 600; font-size: 13px; }

.tbgroup { display: flex; gap: 5px; align-items: center; }
.tbgroup--end { justify-self: end; }
.tb {
  width: 30px; height: 24px; border-radius: 6px;
  display: grid; place-items: center; color: var(--w-fg);
}
.tb svg {
  width: 16px; height: 16px; fill: none; stroke: currentColor;
  stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round;
}
.tb[data-state="off"] { color: var(--w-fg3); }
.tb[data-state="hover"] { background: var(--w-hover); }

/* ---------- tab strip ---------- */
.win__tabs {
  /* The insertion caret is positioned against the strip. */
  position: relative;
  height: 38px; background: var(--w-bar);
  border-bottom: 1px solid var(--w-edge);
  display: flex; align-items: center; gap: 5px;
  padding: 0 8px; overflow: hidden;
}
.wtab {
  height: 27px; padding: 0 10px; border-radius: 7px;
  display: flex; align-items: center; gap: 6px;
  background: var(--w-tab); font-size: 12.5px; white-space: nowrap; flex: none;
}
.wtab[data-live] {
  background: var(--w-tab-live);
  box-shadow: 0 0 0 1px var(--w-btn-edge);
  font-weight: 500;
}
.wtab__x { color: var(--w-fg2); font-size: 11px; }
.wtab__dot { width: 6px; height: 6px; border-radius: 50%; background: var(--w-fg2); }
.wtab__pin { width: 11px; height: 11px; fill: currentColor; opacity: .7; flex: none; }
.groupchip {
  height: 21px; padding: 0 9px; border-radius: 999px;
  /* The app draws the disclosure chevron before the name, not after. */
  display: flex; align-items: center; gap: 5px; flex: none;
  border: 0; margin: 0; font: inherit; font-size: 11.5px;
  -webkit-appearance: none; appearance: none;
  color: color-mix(in srgb, var(--gc, var(--w-accent)) 82%, transparent);
  background: color-mix(in srgb, var(--gc, var(--w-accent)) 12%, transparent);
}

.groupchip__tw { display: block; line-height: 0; }
.groupchip__tw svg {
  display: block; width: 9px; height: 9px;
  fill: none; stroke: currentColor; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
  transition: transform var(--response-quick) var(--ease-damped);
}
/* Folded away: the app turns the chevron from down to right. */
.groupchip[data-collapsed] .groupchip__tw svg { transform: rotate(-90deg); }

/* A group's colour, named once and used by the chip and by the run of tabs
   underneath it, the way the app does it. */
.g-grey   { --gc: #8e8e93; }
.g-blue   { --gc: #3b82f6; }
.g-teal   { --gc: #2aa198; }
.g-green  { --gc: #3fa34d; }
.g-yellow { --gc: #d6a41a; }
.g-orange { --gc: #e0892e; }
.g-red    { --gc: #dc4c3f; }
.g-pink   { --gc: #dd4a7a; }
.g-purple { --gc: #a55ad4; }

/* The underline that says which tabs a group holds. Each tab covers the gap on
   its right, so a run of tabs reads as one bar rather than several stripes. */
.wtab[data-run] { position: relative; }
.wtab[data-run]::after {
  content: ""; position: absolute; bottom: 0; left: 0; right: 0; height: 3px;
  background: color-mix(in srgb, var(--gc) 62%, transparent);
}
.wtab[data-run="start"]::after,
.wtab[data-run="mid"]::after { right: -5px; }
.wtab[data-run="start"]::after,
.wtab[data-run="only"]::after { border-bottom-left-radius: 1.5px; }
.wtab[data-run="end"]::after,
.wtab[data-run="only"]::after { border-bottom-right-radius: 1.5px; }
.win__vrule { width: 1px; height: 17px; background: var(--w-edge); flex: none; margin: 0 3px; }
.win__plus { margin-left: auto; color: var(--w-fg); font-size: 15px; padding: 0 4px; }

/* ---------- find bar ---------- */
.findbar {
  height: 35px; background: var(--w-bar);
  border-bottom: 1px solid var(--w-edge);
  display: flex; align-items: center; gap: 7px;
  padding: 0 10px; font-size: 12px; overflow: hidden;
}
.wfield {
  height: 22px; min-width: 120px; padding: 0 8px;
  border-radius: 5px; background: var(--w-canvas);
  box-shadow: 0 0 0 1px var(--w-btn-edge);
  display: flex; align-items: center; color: var(--w-fg); flex: none;
}
.wfield[data-placeholder] { color: var(--w-fg3); }
.wmini {
  height: 22px; padding: 0 8px; border-radius: 5px; flex: none;
  background: var(--w-btn); box-shadow: 0 0 0 1px var(--w-btn-edge);
  display: flex; align-items: center; gap: 4px; font-size: 12px;
}
.wmini[data-flat] { background: transparent; box-shadow: none; color: var(--w-fg2); }
.wmini[data-on] { background: var(--w-hover); box-shadow: none; }

/* ---------- editor ---------- */
.win__editor { display: grid; grid-template-columns: 40px 1fr; background: var(--w-canvas); }
.win__gutter {
  border-right: 1px solid var(--w-gutter);
  color: var(--w-fg2); text-align: right;
  padding: 6px 8px 8px 0;
  font: 11px/20px var(--mono);
  font-variant-numeric: tabular-nums;
}
.win__code {
  margin: 0; padding: 6px 12px 8px;
  font: 13px/20px var(--mono);
  white-space: pre; overflow-x: auto; color: var(--w-fg);
}
.win__code .cur { background: var(--w-sel); display: block; margin: 0 -12px; padding: 0 12px; }
.caret { display: inline-block; width: 1px; height: 14px; background: currentColor; vertical-align: -2px; }

/* syntax roles, legible on both window appearances */
.tk { color: #a626a4; } .tv { color: #c41a16; } .tn { color: #1c00cf; }
.tc { color: #6e6e73; } .ty { color: #3f6e74; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .win:not(.win--light) .tk { color: #c678dd; }
  :root:not([data-theme="light"]) .win:not(.win--light) .tv { color: #e06c75; }
  :root:not([data-theme="light"]) .win:not(.win--light) .tn { color: #61afef; }
  :root:not([data-theme="light"]) .win:not(.win--light) .tc { color: #7f848e; }
  :root:not([data-theme="light"]) .win:not(.win--light) .ty { color: #56b6c2; }
}

/* The same, chosen explicitly rather than inherited from the system.
   A media query cannot express "Dark on a light Mac". */
:root[data-theme="dark"] .win:not(.win--light) .tk { color: #c678dd; }
  :root[data-theme="dark"] .win:not(.win--light) .tv { color: #e06c75; }
  :root[data-theme="dark"] .win:not(.win--light) .tn { color: #61afef; }
  :root[data-theme="dark"] .win:not(.win--light) .tc { color: #7f848e; }
  :root[data-theme="dark"] .win:not(.win--light) .ty { color: #56b6c2; }

.win--dark .tk { color: #c678dd; } .win--dark .tv { color: #e06c75; }
.win--dark .tn { color: #61afef; } .win--dark .tc { color: #7f848e; }
.win--dark .ty { color: #56b6c2; }

/* ---------- smart action bar ---------- */
.win__bar {
  min-height: 35px; background: var(--w-bar);
  border-top: 1px solid var(--w-edge);
  display: flex; align-items: center; gap: 9px;
  padding: 0 12px; font-size: 12px; color: var(--w-fg2); overflow: hidden;
}
.win__bar .spacer { flex: 1 1 auto; min-width: 6px; }
.wact {
  height: 22px; padding: 0 8px; border-radius: 5px; flex: none;
  display: flex; align-items: center; gap: 5px; color: var(--w-fg);
}
.wact[data-hover] { background: var(--w-hover); }
.wact[data-locked] { color: var(--w-fg3); }
.wpro {
  font-size: 9px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
  padding: 1px 4px; border-radius: 999px;
  background: var(--w-accent-soft); color: var(--w-accent);
}
.wstatus { color: var(--w-fg2); font-variant-numeric: tabular-nums; flex: none; }

/* ---------- inspector column ---------- */
.win__split { display: grid; grid-template-columns: 1fr 300px; }
.win__panel { border-left: 1px solid var(--w-edge); background: var(--w-canvas); }
.win__panelhead {
  height: 32px; background: var(--w-bar);
  border-bottom: 1px solid var(--w-edge);
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 10px; font-weight: 600; font-size: 12.5px; color: var(--w-fg);
}
.win__panelbody { padding: 8px 10px; display: grid; gap: 5px; font-size: 12px; }
.wvalid { display: flex; align-items: center; gap: 6px; color: #1d7a45; font-size: 11.5px; }
.win--dark .wvalid { color: #4ed17f; }
@media (prefers-color-scheme: dark) { .win:not(.win--light) .wvalid { color: #4ed17f; } }

/* The same, chosen explicitly rather than inherited from the system.
   A media query cannot express "Dark on a light Mac".

   The `:root[data-theme="dark"]` half is not optional: without it this matches
   every mockup in every theme, and the dark green intended for a dark panel
   was being painted on a light one. */
:root[data-theme="dark"] .win:not(.win--light) .wvalid { color: #4ed17f; }

.wtree { display: flex; align-items: center; gap: 6px; font: 12px/1.7 var(--mono); white-space: nowrap; }
.wtree__tw { color: var(--w-fg3); width: 10px; flex: none; }
.wtree__meta { color: var(--w-fg3); font-size: 11px; }

/* ---------- content mode header ---------- */
.win__modehead {
  height: 32px; background: var(--w-bar);
  border-bottom: 1px solid var(--w-edge);
  display: flex; align-items: center; gap: 8px; padding: 0 12px;
}
.win__modehead b { font-size: 12.5px; color: var(--w-fg); }
.win__modehead span { font-size: 11px; color: var(--w-fg2); }

/* ---------- log workbench ---------- */
.win__filters {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  padding: 8px 12px; background: var(--w-canvas);
  border-bottom: 1px solid var(--w-edge);
}
.lvlchip {
  height: 20px; padding: 0 8px; border-radius: 999px;
  display: flex; align-items: center; gap: 5px;
  font-size: 11px; font-weight: 500;
  box-shadow: inset 0 0 0 1px currentColor; opacity: .42;
}
.lvlchip[data-on] { opacity: 1; }
.lvlchip i { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.logrows { font: 12px/1.65 var(--mono); padding: 4px 0 8px; }
.logrow { display: flex; align-items: baseline; gap: 8px; padding: 1px 12px; white-space: nowrap; }
.logrow[data-cont] { padding-left: 30px; color: var(--w-fg2); }
.logrow__lvl { flex: none; width: 44px; font-weight: 700; font-size: 11px; }
.logrow__msg { overflow: hidden; text-overflow: ellipsis; }
.logrow__rep {
  font: 600 10px/1 var(--font); padding: 2px 5px; border-radius: 999px;
  background: var(--w-hover); color: var(--w-fg2); flex: none;
}
.hl { background: rgba(255, 214, 10, .34); border-radius: 2px; padding: 0 1px; }
.win--dark .hl { background: rgba(255, 214, 10, .22); }
@media (prefers-color-scheme: dark) { .win:not(.win--light) .hl { background: rgba(255, 214, 10, .22); } }

/* The same, chosen explicitly. See `.wvalid` above for why the
   `:root[data-theme="dark"]` qualifier has to be there. */
:root[data-theme="dark"] .win:not(.win--light) .hl { background: rgba(255, 214, 10, .22); }


.sev-trace { color: #86868b; }
.sev-debug { color: #0a6ed1; } .sev-info { color: #1d7a45; }
.sev-warn { color: #b26205; } .sev-error { color: #c9282d; } .sev-fatal { color: #8b2fb0; }
.win--dark .sev-debug { color: #4da3ff; } .win--dark .sev-info { color: #4ed17f; }
.win--dark .sev-warn { color: #f0a93b; } .win--dark .sev-error { color: #ff6b6f; }
.win--dark .sev-fatal { color: #d08bee; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .win:not(.win--light) .sev-debug { color: #4da3ff; }
  :root:not([data-theme="light"]) .win:not(.win--light) .sev-info { color: #4ed17f; }
  :root:not([data-theme="light"]) .win:not(.win--light) .sev-warn { color: #f0a93b; }
  :root:not([data-theme="light"]) .win:not(.win--light) .sev-error { color: #ff6b6f; }
  :root:not([data-theme="light"]) .win:not(.win--light) .sev-fatal { color: #d08bee; }
}

/* The same, chosen explicitly rather than inherited from the system.
   A media query cannot express "Dark on a light Mac". */
:root[data-theme="dark"] .win:not(.win--light) .sev-debug { color: #4da3ff; }
  :root[data-theme="dark"] .win:not(.win--light) .sev-info { color: #4ed17f; }
  :root[data-theme="dark"] .win:not(.win--light) .sev-warn { color: #f0a93b; }
  :root[data-theme="dark"] .win:not(.win--light) .sev-error { color: #ff6b6f; }
  :root[data-theme="dark"] .win:not(.win--light) .sev-fatal { color: #d08bee; }


/* ---------- compare ---------- */
.win__cmpbar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 8px 12px; font-size: 12px;
  background: var(--w-bar); border-bottom: 1px solid var(--w-edge);
}
.difftable { font: 12px/1.7 var(--mono); }
.diffrow { display: grid; grid-template-columns: 1fr 1fr; }
.diffside { display: grid; grid-template-columns: 30px 1fr; gap: 8px; padding: 0 8px; white-space: pre; overflow: hidden; }
.diffside + .diffside { border-left: 1px solid var(--w-gutter); }
.diffln { color: var(--w-fg3); text-align: right; font-variant-numeric: tabular-nums; }
.d-add { background: rgba(48, 164, 108, .17); }
.d-rem { background: rgba(229, 72, 77, .15); }
.d-chg { background: rgba(224, 134, 0, .17); }
.diffrow[data-focus] { box-shadow: inset 2px 0 0 var(--w-accent); }

/* ---------- two-pane split ---------- */
.win__panes { display: grid; grid-template-columns: 1fr 1fr; }
.wpane + .wpane { border-left: 1px solid var(--w-edge); }
.wpane__bar {
  height: 26px; background: var(--w-bar); border-bottom: 1px solid var(--w-edge);
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 8px; font-size: 11.5px; color: var(--w-fg2);
}

/* ---------- table view ---------- */
.wtable { font-size: 12px; width: 100%; border-collapse: collapse; }
.wtable th, .wtable td {
  text-align: left; padding: 5px 10px;
  border-bottom: 1px solid var(--w-gutter); white-space: nowrap;
}
.wtable thead th { background: var(--w-bar); color: var(--w-fg2); font-weight: 600; font-size: 11px; }
.wtable td { font-family: var(--mono); color: var(--w-fg); }

@media (max-width: 720px) {
  .win__split, .win__panes { grid-template-columns: 1fr; }
  .win__panel, .wpane + .wpane { border-left: 0; border-top: 1px solid var(--w-edge); }
  .win__code, .logrows, .difftable { font-size: 11.5px; }
}

/* ── Mockup utilities ────────────────────────────────────────────────────
   Named in place of `style` attributes so pages stay CSP-clean. */
.spacer--grow { flex: 1; }
.wclose { color: var(--w-fg3); }
.wtree--1 { padding-left: 14px; }
.wtree--2 { padding-left: 32px; }
.wtree--r { padding-left: 16px; }
.wtree__acts { display: flex; gap: 6px; margin-top: 6px; }

/* ── validation ──────────────────────────────────────────────────────────
   The status chip that lives in the window's action bar, and the issue rows
   in the panel beside the editor. Semantic colour (good / warning / critical)
   is a separate axis from the accent, and every state is carried by its glyph
   and its words as well as its colour. */
.wchip {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 1px 7px; border-radius: 999px;
  font-size: 11px; font-weight: 500;
  white-space: nowrap;
}
.wchip::before { font-size: 10px; }
.wchip[data-state="pass"] { color: #1d7a45; background: rgba(29, 122, 69, .12); }
.wchip[data-state="pass"]::before { content: "\2713"; }
.wchip[data-state="warn"] { color: #a2650a; background: rgba(162, 101, 10, .13); }
.wchip[data-state="warn"]::before { content: "\26A0"; }
.wchip[data-state="fail"] { color: #c0362c; background: rgba(192, 54, 44, .12); }
.wchip[data-state="fail"]::before { content: "\2715"; }

/* Pinned-dark windows, in any page theme. */
.win--dark .wchip[data-state="pass"] { color: #4ed17f; background: rgba(78, 209, 127, .16); }
.win--dark .wchip[data-state="warn"] { color: #ffd60a; background: rgba(255, 214, 10, .16); }
.win--dark .wchip[data-state="fail"] { color: #ff6961; background: rgba(255, 105, 97, .16); }
.win--dark .wissue[data-severity="error"] .wissue__icon { color: #ff6961; }
.win--dark .wissue[data-severity="warning"] .wissue__icon { color: #ffd60a; }

/* Theme-following windows. This block has to stay inside the media query: the
   :root:not([data-theme="light"]) guard is true whenever nothing is stamped,
   which is most of the time, so on its own it would apply the dark palette in
   light mode and outrank the light rules on specificity. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .win:not(.win--light) .wchip[data-state="pass"] { color: #4ed17f; background: rgba(78, 209, 127, .16); }
  :root:not([data-theme="light"]) .win:not(.win--light) .wchip[data-state="warn"] { color: #ffd60a; background: rgba(255, 214, 10, .16); }
  :root:not([data-theme="light"]) .win:not(.win--light) .wchip[data-state="fail"] { color: #ff6961; background: rgba(255, 105, 97, .16); }
  :root:not([data-theme="light"]) .win:not(.win--light) .wissue[data-severity="error"] .wissue__icon { color: #ff6961; }
  :root:not([data-theme="light"]) .win:not(.win--light) .wissue[data-severity="warning"] .wissue__icon { color: #ffd60a; }
}

/* The same, chosen explicitly rather than inherited from the system.
   A media query cannot express "Dark on a light Mac". */
:root[data-theme="dark"] .win:not(.win--light) .wchip[data-state="pass"] { color: #4ed17f; background: rgba(78, 209, 127, .16); }
  :root[data-theme="dark"] .win:not(.win--light) .wchip[data-state="warn"] { color: #ffd60a; background: rgba(255, 214, 10, .16); }
  :root[data-theme="dark"] .win:not(.win--light) .wchip[data-state="fail"] { color: #ff6961; background: rgba(255, 105, 97, .16); }
  :root[data-theme="dark"] .win:not(.win--light) .wissue[data-severity="error"] .wissue__icon { color: #ff6961; }
  :root[data-theme="dark"] .win:not(.win--light) .wissue[data-severity="warning"] .wissue__icon { color: #ffd60a; }


.wissues { display: grid; gap: 0; }
.wissue {
  display: grid; grid-template-columns: 14px minmax(0, 1fr);
  gap: 8px; padding: 8px 0;
  border-bottom: 1px solid var(--w-edge);
  font-size: 12px;
}
.wissue:last-child { border-bottom: 0; }
.wissue__icon { font-size: 11px; line-height: 1.5; }
.wissue[data-severity="error"] .wissue__icon { color: #c0362c; }
.wissue[data-severity="warning"] .wissue__icon { color: #a2650a; }
.wissue[data-severity="notice"] .wissue__icon { color: var(--w-fg3); }
.win--dark .wissue[data-severity="error"] .wissue__icon { color: #ff6961; }
.win--dark .wissue[data-severity="warning"] .wissue__icon { color: #ffd60a; }
.wissue__msg { color: var(--w-fg); }
.wissue__at { color: var(--w-fg2); font-family: var(--mono); font-size: 11px; }
.wissue__hint { color: var(--w-fg2); }

.wmenu {
  display: grid; gap: 1px;
  /* A menu is as wide as its longest item, not as wide as the window. */
  width: max-content; max-width: 100%;
  padding: 5px; border-radius: 8px;
  background: var(--w-btn);
  box-shadow: 0 0 0 1px var(--w-btn-edge), var(--shadow-md);
  font-size: 12px;
}
.wmenu__item {
  display: flex; align-items: center; justify-content: space-between; gap: 18px;
  padding: 4px 8px; border-radius: 5px; color: var(--w-fg);
}
.wmenu__item[data-on] { background: var(--w-accent-soft); }
.wmenu__item[data-locked] { color: var(--w-fg3); }
.wmenu__key { color: var(--w-fg2); font-family: var(--mono); font-size: 11px; }
.wmenu__sep { height: 1px; margin: 4px 2px; background: var(--w-edge); }

/* ── the hero's several documents ─────────────────────────────────────────
   One window, one tab strip, and a document behind each tab. The documents
   are stacked in a single grid cell so the window is as tall as the tallest
   of them and never resizes when the reader switches — a hero that jumps
   pushes the page out from under whatever they were reading.

   `visibility: hidden` rather than `display: none` is what keeps the
   inactive documents contributing their height while staying out of the
   accessibility tree and out of the tab order. */
.win__stage { display: grid; }
.win__doc {
  grid-area: 1 / 1;
  /* Content, then the action bar pinned to the bottom edge — so a short
     document leaves empty editor above the bar, the way the app does. */
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  min-height: 336px;
}
.win__doc > .win__editor,
.win__doc > .win__split,
.win__doc > .win__mode { min-height: 0; }
.win__mode {
  display: grid;
  grid-template-rows: auto auto minmax(0, 1fr);
  align-content: start;
  background: var(--w-canvas);
  overflow: hidden;
}
.win__doc[aria-hidden="true"] {
  opacity: 0;
  transform: translateY(4px);
  visibility: hidden;
  pointer-events: none;
}

/* Motion only once the script is driving the strip. Entering is the longer
   half: it is the part a reader watches. Leaving gets out of the way. */
[data-hero-ready] .win__doc {
  transition: opacity .18s var(--ease-damped), transform .18s var(--ease-damped);
}
[data-hero-ready] .win__doc[aria-hidden="true"] {
  transition: opacity .12s var(--ease-damped),
              transform .12s var(--ease-damped),
              visibility 0s linear .12s;
}
@media (prefers-reduced-motion: reduce) {
  .win__doc, .win__doc[aria-hidden="true"] { transform: none; }
}

/* Tabs are buttons here, not decoration. */
.win__tabs button.wtab {
  border: 0; margin: 0; padding: 0 10px;
  font: inherit; font-size: 12.5px; color: inherit;
  -webkit-appearance: none; appearance: none;
}
.wtab[aria-selected="true"] {
  background: var(--w-tab-live);
  box-shadow: 0 0 0 1px var(--w-btn-edge);
}
[data-hero-ready] .wtab[role="tab"] {
  cursor: pointer;
  transition: background-color var(--response-quick) var(--ease-damped),
              box-shadow var(--response-quick) var(--ease-damped);
}
/* Touch fires a false hover on tap, so the affordance is for real pointers. */
@media (hover: hover) and (pointer: fine) {
  [data-hero-ready] .wtab[role="tab"]:hover:not([aria-selected="true"]) {
    background: var(--w-tab-live);
  }
}
.wtab[role="tab"]:focus-visible {
  outline: 2px solid var(--w-accent);
  outline-offset: 1px;
}

/* The action bar's overflow control, which the app draws as an ellipsis. */
.wact--more { color: var(--w-fg2); letter-spacing: .06em; }

/* ── a pointer the reader did not move ────────────────────────────────────
   The window advancing on its own says the tabs change. It does not say the
   reader is the one who can change them. So for the length of the lap the
   demo shows what it is asking for: a cursor travels to the next tab, the tab
   lights the way it lights under a real pointer, and the cursor presses it.

   It exists only where a real cursor does, only while the demo is running,
   and never again once the reader takes over. */
.win__ghost {
  position: absolute;
  left: 0; top: 0;
  width: 14px; height: 20px;
  z-index: 2;
  pointer-events: none;
  opacity: 0;
  /* Must match TRAVEL in hero.js, and the lifted tab's transition below: the
     cursor and anything it is carrying are one movement. */
  transition: transform .52s var(--ease-travel),
              opacity .22s var(--ease-damped);
}
.win__ghost[data-on] { opacity: 1; }
/* macOS draws its arrow white with a dark border in either appearance, so
   this one does too rather than following the window's palette. */
.win__ghost svg {
  display: block; width: 14px; height: 20px;
  fill: #fff;
  stroke: rgba(0, 0, 0, .55); stroke-width: 1.3; stroke-linejoin: round;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .45));
}
/* The press, drawn as a ring leaving the click rather than as a flash. */
.win__ghost__ring {
  position: absolute; left: -6px; top: -6px;
  width: 16px; height: 16px; border-radius: 50%;
  border: 1.5px solid var(--w-accent);
  opacity: 0;
  transform: scale(.35);
}
.win__ghost[data-press] .win__ghost__ring {
  animation: ghost-press .44s var(--ease-damped) forwards;
}
@keyframes ghost-press {
  from { opacity: .9; transform: scale(.35); }
  to   { opacity: 0;  transform: scale(1.6); }
}

/* The tab under the ghost answers it, so the press has somewhere to land. */
.wtab[data-ghost]:not([aria-selected="true"]) { background: var(--w-tab-live); }
.wtab[data-ghost-press] { background: var(--w-hover); }

/* No cursor to imitate, or no appetite for motion: the lap does not run, so
   neither does this. */
@media (prefers-reduced-motion: reduce) { .win__ghost { display: none; } }
@media not all and (hover: hover) and (pointer: fine) {
  .win__ghost { display: none; }
}

/* ── the second act: the tabs themselves ──────────────────────────────────
   Once the lap has shown that the bar follows the document, the demo goes on
   to the thing a still frame can never show: a tab dragged into a group, the
   group folded away and opened again, and renamed. These are the pieces that
   act needs — a lifted tab, a drop target, a context menu and an alert. */

/* Reordering is a FLIP: the strip mutates, every tab is put back where it
   was with a transform, and released. Only `transform` moves, so no layout
   runs per frame. */
.wtab[data-flip] { transition: transform .34s var(--ease-damped); }

/* The tab that steps aside to open the gap a dragged tab is heading for. */
.wtab[data-slide] { transition: transform .3s var(--ease-damped); }

/* The tab being dragged, held off the strip the way a real drag holds it.
   The duration has to match TRAVEL in hero.js: the cursor and the tab it is
   carrying are one movement, and a few milliseconds of disagreement is
   exactly what makes a drag look like two things pretending. */
.wtab[data-lift] {
  box-shadow: 0 0 0 1px var(--w-btn-edge), 0 6px 16px rgba(0, 0, 0, .35);
  background: var(--w-tab-live);
  z-index: 3;
  position: relative;
  transition: transform .52s var(--ease-travel),
              box-shadow .16s var(--ease-damped);
}

/* Where the tab would land. The app draws a 3pt accent capsule on the leading
   edge of the tab it would insert before, half the item spacing out from it. */
.wdrop {
  position: absolute;
  left: 0; top: 8px;
  width: 3px; height: 22px;
  border-radius: 999px;
  background: var(--w-accent);
  /* Above the held tab: the caret is the message, and a caret hidden under
     the thing it is guiding says nothing. */
  z-index: 4;
  pointer-events: none;
  opacity: 0;
  transform: scaleY(.4);
  transition: opacity .14s var(--ease-damped), transform .14s var(--ease-damped);
}
.wdrop[data-on] { opacity: 1; transform: scaleY(1); }

/* A tab hidden because its group is folded away. `display: none` rather than
   the documents' `visibility`: here the row must actually close up. */
.wtab[data-folded] { display: none; }

/* The context menu, which comes out of the chip it belongs to — placed with
   left/top once, animated only on transform and opacity. */
.win__pop {
  position: absolute;
  left: 0; top: 0;
  z-index: 4;
  transform-origin: top left;
  opacity: 0;
  transform: scale(.95);
  pointer-events: none;
  transition: opacity .16s var(--ease-damped), transform .16s var(--ease-damped);
}
.win__pop[data-on] { opacity: 1; transform: scale(1); }

/* The rename alert. A modal is not anchored to a trigger, so it stays
   centred and scales from its own middle. */
.win__scrim {
  position: absolute; inset: 0; z-index: 5;
  display: grid; place-items: center;
  background: rgba(0, 0, 0, .18);
  opacity: 0; pointer-events: none;
  transition: opacity .2s var(--ease-damped);
}
.win__scrim[data-on] { opacity: 1; }
.walert {
  width: 270px; padding: 16px 18px 14px;
  border-radius: 12px; text-align: center;
  background: var(--w-chrome);
  box-shadow: 0 0 0 1px var(--w-btn-edge), var(--shadow-lg);
  display: grid; gap: 8px;
  transform: scale(.96);
  transition: transform .2s var(--ease-damped);
}
.win__scrim[data-on] .walert { transform: scale(1); }
.walert__title { font-weight: 600; font-size: 13px; color: var(--w-fg); }
.walert__msg { font-size: 11.5px; color: var(--w-fg2); }
.walert__field {
  height: 22px; padding: 0 7px; border-radius: 5px;
  background: var(--w-canvas); box-shadow: 0 0 0 1px var(--w-btn-edge);
  display: flex; align-items: center; gap: 1px;
  font-size: 12px; color: var(--w-fg); text-align: left;
}
.walert__acts { display: flex; gap: 8px; }
.walert__acts .wmini { flex: 1; justify-content: center; }
.walert__ok { background: var(--w-accent); color: #fff; box-shadow: none; }

@media (prefers-reduced-motion: reduce) {
  .win__pop, .win__scrim, .walert, .wtab[data-lift], .wtab[data-slide], .wdrop { transition: none; }
}

/* ── the strip, once the reader has it ───────────────────────────────────
   The script is a demonstration; these are the controls it was demonstrating.
   They work from the first frame, not only after the demo has run its course:
   tabs drag into and out of the group, and the chip folds it away. */
[data-hero-ready] .win__tabs { user-select: none; -webkit-user-select: none; }
[data-hero-ready] .groupchip { cursor: pointer; }
@media (hover: hover) and (pointer: fine) {
  [data-hero-ready] .groupchip:hover { background: color-mix(in srgb, var(--gc) 20%, transparent); }
}
.groupchip:focus-visible { outline: 2px solid var(--w-accent); outline-offset: 1px; }

/* While a tab is being carried, the whole strip says so. */
.win__tabs[data-dragging] { cursor: grabbing; }
.win__tabs[data-dragging] * { cursor: grabbing; }
