/* ==========================================================================
   Gas Processing Facilities — interactive visualization
   Source of truth for markup: resources/js/gas-processing/ (generated blade
   partials + public/site/js/gas-processing.js). This file is hand-authored.
   Motion tokens mirror resources/js/gas-processing/config.ts.
   ========================================================================== */

.gpx {
  --gp-blue: #015A8D;
  --gp-blue-l: #0a6ea6;
  --gp-navy: #0B2E4F;
  --gp-navy-d: #013a5c;
  --gp-gold: #F1C42B;
  --gp-ink: #232323;
  --gp-muted: #6f6f6f;
  --gp-canvas: #F6F9FB;
  --gp-card: #ffffff;
  --gp-line: #E3E9EE;
  --gp-export: #1E7D46;
  --gp-fuel: #46759B;
  --gp-lpg: #7B2D8E;
  --gp-ngl: #7A4A21;
  --gp-branch: #D97706;
  --gp-utility: #C0392B;
  --gp-dim-hover: 0.55;
  --gp-dim-trace: 0.12;
  --gp-shadow-rest: 0 6px 18px rgba(1, 58, 92, 0.08);
  --gp-shadow-hover: 0 14px 30px rgba(1, 58, 92, 0.16);
  --gp-ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --gp-ease-inout: cubic-bezier(0.65, 0, 0.35, 1);
  --gp-t-micro: 120ms;
  --gp-t-state: 240ms;
  --gp-t-panel: 320ms;
  --gp-t-draw: 700ms;
  --gp-t-node: 400ms;
  --gp-t-segment: 350ms;
  /* Flow: one dash+gap cycle (7px + 15px = 22px) travels per --gp-flow-dur.
     A FIXED pixel delta per cycle = identical particle VELOCITY on every
     segment regardless of its length. One duration, one place. */
  --gp-flow-dash: 7;
  --gp-flow-gap: 15;
  --gp-flow-dur: 900ms;
  /* Idle equipment loops (per-unit ambient motion) */
  --gp-idle: 4200ms;
  --gp-idle-slow: 6500ms;
  font-family: 'Roboto', sans-serif;
  color: var(--gp-ink);
}
.gpx *, .gpx *:before, .gpx *:after { box-sizing: border-box; }

/* --------------------------------------------------------------------------
   Hero banner (matches the site's bespoke-page hero language)
   -------------------------------------------------------------------------- */
.gpx-hero { position: relative; overflow: hidden; min-height: 460px; display: flex; align-items: center; padding: 300px 0 100px; text-align: center; color: #fff; }
.gpx-hero__bg { position: absolute; inset: 0; z-index: 0; background: radial-gradient(120% 90% at 78% 8%, var(--gp-blue-l) 0%, var(--gp-blue) 42%, var(--gp-navy-d) 100%); }
.gpx-hero__bg:after { content: ""; position: absolute; inset: 0; background: linear-gradient(180deg, rgba(1,58,92,.35) 0%, rgba(1,58,92,0) 30%), linear-gradient(0deg, rgba(1,58,92,.55) 0%, rgba(1,58,92,0) 26%); }
.gpx-hero__mark { position: absolute; right: 2%; bottom: -40px; font-size: 250px; color: #fff; opacity: .05; z-index: 0; transform: rotate(-6deg); }
.gpx-hero__inner { position: relative; z-index: 1; width: 100%; }
.gpx-eyebrow { display: inline-block; font-family: 'Montserrat', sans-serif; font-size: 12px; font-weight: 600; letter-spacing: .24em; text-transform: uppercase; color: var(--gp-gold); margin-bottom: 14px; }
.gpx-hero h1 { font-family: 'Montserrat', sans-serif; font-size: 44px; font-weight: 600; line-height: 1.12; margin: 0 auto; letter-spacing: -.5px; max-width: 18ch; color: #fff; }
.gpx-hero h1:after { content: ""; display: block; width: 60px; height: 4px; background: var(--gp-gold); border-radius: 3px; margin: 16px auto 0; }
.gpx-hero__sub { font-size: 17.5px; font-weight: 300; line-height: 1.75; opacity: .92; margin: 18px auto 0; max-width: 62ch; }

/* --------------------------------------------------------------------------
   Section shell
   -------------------------------------------------------------------------- */
.gpx-section { background: var(--gp-canvas); padding: 46px 0 84px; }
.gp-hintbar { display: flex; align-items: center; justify-content: center; gap: 9px; font-size: 15px; color: var(--gp-muted); margin: 0 0 18px; }
.gp-hintbar .fas { color: var(--gp-blue); font-size: 14px; }

.gp-canvas { position: relative; background: var(--gp-card); border: 1px solid var(--gp-line); border-radius: 16px; box-shadow: 0 22px 50px rgba(1, 58, 92, 0.10); padding: 26px 18px; overflow: hidden; }
.gp-svg { display: block; width: 100%; height: auto; }
.gp-svg text { font-family: 'Montserrat', 'Roboto', sans-serif; }
.gp-svg-v { display: none; }

/* Below the desktop container width the horizontal train cannot be shown at a
   legible size without panning, and a horizontal scrollbar is worse than a
   re-flow: use the vertical timeline instead. Nothing ever scrolls sideways.
   (Deviates from the plan's tablet pan-canvas - see the plan appendix.) */
@media (max-width: 1199px) {
  .gp-svg-h { display: none; }
  .gp-svg-v { display: block; max-width: 470px; margin: 0 auto; }
  .gp-canvas { padding: 22px 14px; }
}
@media (max-width: 767px) {
  .gp-svg-v { max-width: 420px; }
  .gp-canvas { padding: 18px 8px; }
}

/* --------------------------------------------------------------------------
   Nodes — cards, caps, badges, glyphs
   -------------------------------------------------------------------------- */
.gp-node { cursor: pointer; transition: opacity var(--gp-t-state) var(--gp-ease-inout), transform var(--gp-t-micro) var(--gp-ease-out); }
.gp-node:focus { outline: none; }
.gp-node:focus-visible .gp-card,
.gp-node:focus-visible .gp-port-box,
.gp-node:focus-visible .gp-source-box { stroke: var(--gp-gold); stroke-width: 3; }

.gp-card { fill: var(--gp-card); stroke: var(--gp-line); stroke-width: 1.25; filter: drop-shadow(0 5px 12px rgba(1, 58, 92, 0.10)); transition: filter var(--gp-t-micro) var(--gp-ease-out), stroke var(--gp-t-micro); }
.gp-cap { fill: var(--gp-navy); }
.gp-cap-label { fill: #fff; font-size: 13px; font-weight: 700; letter-spacing: .035em; }
.gp-badge circle { fill: var(--gp-gold); }
.gp-badge text { fill: var(--gp-navy); font-size: 12.5px; font-weight: 700; }
.gp-hit { fill: transparent; stroke: none; }

.gp-glyph { color: var(--gp-blue); }
.gp-glyph * { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.gp-glyph .gp-g-soft { opacity: .45; stroke-width: 1.6; }

/* unit hover/selection */
.gp-unit:hover .gp-card, .gp-unit.is-hot .gp-card { filter: drop-shadow(0 12px 22px rgba(1, 58, 92, 0.20)); }
.gp-unit:hover, .gp-unit.is-hot { transform: translateY(-3px); }
.gp-unit.is-sel { transform: translateY(-3px); }
.gp-unit.is-sel .gp-card { stroke: var(--gp-gold); stroke-width: 2.5; }

/* source chip */
.gp-source-box { fill: var(--gp-navy); stroke: none; }
.gp-source-label { fill: #fff; font-size: 12px; font-weight: 700; letter-spacing: .08em; }
.gp-source { cursor: default; }

/* product ports */
.gp-port-box { fill: var(--gp-card); stroke: var(--gp-line); stroke-width: 1.25; filter: drop-shadow(0 5px 12px rgba(1, 58, 92, 0.10)); transition: filter var(--gp-t-micro) var(--gp-ease-out), stroke var(--gp-t-micro); }
.gp-port-name { font-size: 16px; font-weight: 700; letter-spacing: .04em; }
.gp-port-dest { font-family: 'Roboto', sans-serif; font-size: 12.5px; fill: var(--gp-muted); }
/* Product highlight: each port carries a soft tint of its own colour */
.gp-port[data-color="export"] .gp-port-box { fill: #EDF6F1; stroke: rgba(30, 125, 70, .45); stroke-width: 1.6; }
.gp-port[data-color="fuel"] .gp-port-box { fill: #F0F5F9; stroke: rgba(70, 117, 155, .40); stroke-width: 1.4; }
.gp-port[data-color="lpg"] .gp-port-box { fill: #F7F0F9; stroke: rgba(123, 45, 142, .40); stroke-width: 1.6; }
.gp-port[data-color="ngl"] .gp-port-box { fill: #F7F1EA; stroke: rgba(122, 74, 33, .40); stroke-width: 1.6; }
.gp-port .gp-glyph { color: var(--gp-muted); }
.gp-port[data-color="export"] .gp-port-name, .gp-port[data-color="export"] .gp-glyph { fill: var(--gp-export); color: var(--gp-export); }
.gp-port[data-color="fuel"] .gp-port-name, .gp-port[data-color="fuel"] .gp-glyph { fill: var(--gp-fuel); color: var(--gp-fuel); }
.gp-port[data-color="lpg"] .gp-port-name, .gp-port[data-color="lpg"] .gp-glyph { fill: var(--gp-lpg); color: var(--gp-lpg); }
.gp-port[data-color="ngl"] .gp-port-name, .gp-port[data-color="ngl"] .gp-glyph { fill: var(--gp-ngl); color: var(--gp-ngl); }
.gp-port[data-color="export"] .gp-port-bar { fill: var(--gp-export); }
.gp-port[data-color="fuel"] .gp-port-bar { fill: var(--gp-fuel); }
.gp-port[data-color="lpg"] .gp-port-bar { fill: var(--gp-lpg); }
.gp-port[data-color="ngl"] .gp-port-bar { fill: var(--gp-ngl); }
.gp-port:not(.gp-traceable) { cursor: default; }
.gp-traceable:hover, .gp-traceable.is-hot { transform: translateY(-3px); }
.gp-traceable:hover .gp-port-box { filter: drop-shadow(0 12px 22px rgba(1, 58, 92, 0.20)); }

/* --------------------------------------------------------------------------
   Pipes, particles, arrowheads, trace lines
   -------------------------------------------------------------------------- */
/* Base pipe: static, low opacity — the flow layer on top carries the energy */
.gp-pipe { fill: none; stroke-width: 3; stroke-linecap: round; stroke-opacity: .30; }
.gp-edge[data-color="main"] .gp-pipe { stroke: var(--gp-blue); }
.gp-edge[data-color="branch"] .gp-pipe { stroke: var(--gp-branch); }
.gp-edge[data-color="export"] .gp-pipe { stroke: var(--gp-export); }
.gp-edge[data-color="fuel"] .gp-pipe { stroke: var(--gp-fuel); }
.gp-edge[data-color="lpg"] .gp-pipe { stroke: var(--gp-lpg); }
.gp-edge[data-color="ngl"] .gp-pipe { stroke: var(--gp-ngl); }

/* Terminal arrowheads pulse in sync with the dash cadence arriving at them
   (option b — applied consistently; no travelling arrows). The pulse is on
   the INNER path; the wrapper <g> owns the positioning transform. */
.gp-arrowhead { stroke: none; transform-box: fill-box; transform-origin: center; animation: gp-arrive var(--gp-flow-dur) linear infinite; }
@keyframes gp-arrive { 0% { opacity: .55; transform: scale(1); } 14% { opacity: 1; transform: scale(1.22); } 34% { opacity: .8; transform: scale(1); } 100% { opacity: .55; transform: scale(1); } }
.gp-edge[data-color="main"] .gp-arrowhead { fill: var(--gp-blue); }
.gp-edge[data-color="branch"] .gp-arrowhead { fill: var(--gp-branch); }
.gp-edge[data-color="export"] .gp-arrowhead { fill: var(--gp-export); }
.gp-edge[data-color="fuel"] .gp-arrowhead { fill: var(--gp-fuel); }
.gp-edge[data-color="lpg"] .gp-arrowhead { fill: var(--gp-lpg); }
.gp-edge[data-color="ngl"] .gp-arrowhead { fill: var(--gp-ngl); }

/* Gas flow: identical dash pattern everywhere, per-edge colour, constant
   velocity (fixed -22px cycle over --gp-flow-dur). The glow twin is a wide
   faint duplicate — deliberately NOT filter:drop-shadow on an animated path. */
.gp-flow, .gp-flow-glow { fill: none; stroke-linecap: round; stroke-dasharray: var(--gp-flow-dash) var(--gp-flow-gap); animation: gp-drift var(--gp-flow-dur) linear infinite; }
.gp-flow { stroke-width: 3.4; stroke-opacity: .95; }
.gp-flow-glow { stroke-width: 7.5; stroke-opacity: .18; }
@keyframes gp-drift { to { stroke-dashoffset: -22; } }
.gp-edge[data-color="main"] .gp-flow, .gp-edge[data-color="main"] .gp-flow-glow { stroke: var(--gp-blue); }
.gp-edge[data-color="branch"] .gp-flow, .gp-edge[data-color="branch"] .gp-flow-glow { stroke: var(--gp-branch); }
.gp-edge[data-color="export"] .gp-flow, .gp-edge[data-color="export"] .gp-flow-glow { stroke: var(--gp-export); }
.gp-edge[data-color="fuel"] .gp-flow, .gp-edge[data-color="fuel"] .gp-flow-glow { stroke: var(--gp-fuel); }
.gp-edge[data-color="lpg"] .gp-flow, .gp-edge[data-color="lpg"] .gp-flow-glow { stroke: var(--gp-lpg); }
.gp-edge[data-color="ngl"] .gp-flow, .gp-edge[data-color="ngl"] .gp-flow-glow { stroke: var(--gp-ngl); }

/* Off-screen: pause every loop in the diagram (IntersectionObserver toggles
   .gp-live). play-state preserves phase instead of restarting on re-entry. */
.gp-diagram:not(.gp-live) .gp-svg *,
.gp-diagram:not(.gp-live) .gp-utilities .fas { animation-play-state: paused !important; }

/* trace overlay: product-coloured, revealed segment by segment */
/* One-shot pulse travelling FORWARDS (inlet → product) — the "how it's
   made" story — then settling into the highlighted steady state. Keyframe
   animation, not a transition: restarts deterministically when the class
   applies, honours per-segment animation-delay, 'both' fill holds states. */
.gp-traceline { fill: none; stroke-width: 5; stroke-linecap: round; stroke-dasharray: 1 1; stroke-dashoffset: 1; opacity: 0; }
.gp-tracing .gp-edge.is-route .gp-traceline { opacity: 1; animation: gp-sweep var(--gp-t-segment) linear both; }
@keyframes gp-sweep { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
.gp-tracing.gp-trace-export .is-route .gp-traceline { stroke: var(--gp-export); }
.gp-tracing.gp-trace-lpg .is-route .gp-traceline { stroke: var(--gp-lpg); }
.gp-tracing.gp-trace-ngl .is-route .gp-traceline { stroke: var(--gp-ngl); }

/* --------------------------------------------------------------------------
   Focus states of the whole canvas: hover dim / selection hold / trace mode
   -------------------------------------------------------------------------- */
/* Hover: unrelated content drops to 25%; the hovered unit's edges
   accelerate (0.4x duration = 2.5x velocity) and brighten. Transitioned,
   never snapped. */
.gp-hot .gp-node:not(.is-hot):not(.is-sel),
.gp-hot .gp-edge:not(.is-hot) { opacity: .25; }
.gp-edge.is-hot .gp-flow, .gp-edge.is-hot .gp-flow-glow { animation-duration: calc(var(--gp-flow-dur) * 0.4); }
.gp-edge.is-hot .gp-flow { stroke-width: 4; }
.gp-edge.is-hot .gp-flow-glow { stroke-opacity: .32; }
.gp-edge.is-hot .gp-pipe { stroke-opacity: .5; }
.gp-has-sel .gp-node:not(.is-sel):not(.is-hot),
.gp-has-sel .gp-edge:not(.is-hot) { opacity: .4; }
.gp-edge { transition: opacity var(--gp-t-state) var(--gp-ease-inout); }
.gp-tracing .gp-node:not(.is-route) { opacity: var(--gp-dim-trace); }
.gp-tracing .gp-edge:not(.is-route) { opacity: var(--gp-dim-trace); }
.gp-tracing .gp-node.is-route { opacity: 1; }
.gp-tracing .gp-flow { animation-play-state: paused; }
.gp-tracing .gp-edge.is-route .gp-flow { animation-play-state: running; }

/* --------------------------------------------------------------------------
   Entrance choreography (gated on .gp-js so no-JS renders complete)
   -------------------------------------------------------------------------- */
.gp-js:not(.gp-in) .gp-node { opacity: 0; transform: translateY(8px) scale(.96); }
.gp-js:not(.gp-in) .gp-pipe { stroke-dasharray: 1 1; stroke-dashoffset: 1; }
.gp-js:not(.gp-in) .gp-arrow { opacity: 0; }
.gp-js:not(.gp-in) .gp-flow, .gp-js:not(.gp-in) .gp-flow-glow { opacity: 0; }
.gp-js.gp-in:not(.gp-settled) .gp-node { transition: opacity var(--gp-t-node) var(--gp-ease-out), transform var(--gp-t-node) var(--gp-ease-out); }
.gp-js.gp-in .gp-pipe { stroke-dasharray: 1 1; stroke-dashoffset: 0; transition: stroke-dashoffset var(--gp-t-draw) var(--gp-ease-out); }
.gp-js.gp-in .gp-arrow { opacity: 1; transition: opacity 200ms var(--gp-ease-out); }
.gp-js.gp-in .gp-flow, .gp-js.gp-in .gp-flow-glow { opacity: 1; transition: opacity 300ms var(--gp-ease-out); }
.gp-settled .gp-pipe { stroke-dasharray: none; transition: none; }

/* --------------------------------------------------------------------------
   Per-unit idle motion — one distinct low-amplitude loop per unit.
   RULES: animate INNER glyph parts only (a CSS transform on the positioned
   glyph group overrides its SVG translate — the flying-fan bug); negative
   animation-delays desynchronise every instance; :not(.gp-live) pauses all.
   -------------------------------------------------------------------------- */

/* Compressors — impeller fan (export offset in phase from inlet) */
.gp-rotor { transform-box: fill-box; transform-origin: center; animation: gp-spin 3s linear infinite; }
[data-node="export_compressors"] .gp-rotor { animation-delay: -1.4s; }
@keyframes gp-spin { to { transform: rotate(360deg); } }

/* Cryogenic — snowflake rotates very slowly with a cold shimmer */
.gp-frost { transform-box: fill-box; transform-origin: center; animation: gp-frost-turn 26s linear infinite, gp-shimmer var(--gp-idle) var(--gp-ease-inout) infinite; }
@keyframes gp-frost-turn { to { transform: rotate(360deg); } }
@keyframes gp-shimmer { 50% { opacity: .6; } }

/* Inlet separation — liquid level drifting inside the vessel */
.gp-level { animation: gp-drift-y var(--gp-idle) var(--gp-ease-inout) infinite alternate; animation-delay: -1.1s; }
@keyframes gp-drift-y { from { transform: translateY(-1.1px); } to { transform: translateY(1.1px); } }

/* Mercury removal — faint band descending through each bed */
.gp-band { fill: currentColor; stroke: none !important; opacity: 0; animation: gp-descend var(--gp-idle) linear infinite; }
.gp-band-2 { animation-delay: -2.1s; }
@keyframes gp-descend { 0% { transform: translateY(0); opacity: 0; } 12% { opacity: .4; } 78% { opacity: .4; } 100% { transform: translateY(19px); opacity: 0; } }

/* Sweetening — small bubbles rising in the contactor column */
.gp-bubble { animation: gp-rise 3.8s linear infinite; opacity: 0; }
.gp-bubble-2 { animation-delay: -1.3s; }
.gp-bubble-3 { animation-delay: -2.5s; }
@keyframes gp-rise { 0% { transform: translateY(0); opacity: 0; } 12% { opacity: .8; } 82% { opacity: .8; } 100% { transform: translateY(-23px); opacity: 0; } }

/* Dehydration — moisture fading top to bottom (top beds dry first) */
.gp-dry-t { animation: gp-dry var(--gp-idle) var(--gp-ease-inout) infinite alternate; }
.gp-dry-b { animation: gp-dry var(--gp-idle) var(--gp-ease-inout) infinite alternate; animation-delay: -2.1s; }
@keyframes gp-dry { from { opacity: .5; } to { opacity: .14; } }

/* Debutanizer — tray lines lighting sequentially bottom to top */
.gp-tray-1, .gp-tray-2, .gp-tray-3, .gp-tray-4 { animation: gp-tray 3.2s var(--gp-ease-inout) infinite; }
.gp-tray-1 { animation-delay: 0s; }
.gp-tray-2 { animation-delay: .4s; }
.gp-tray-3 { animation-delay: .8s; }
.gp-tray-4 { animation-delay: 1.2s; }
@keyframes gp-tray { 0%, 100% { opacity: .4; } 18% { opacity: 1; } 40% { opacity: .4; } }

/* Storage (LPG spheres / NGL bullet) — fill level breathing, barely */
.gp-lvl { animation: gp-breathe-lvl var(--gp-idle-slow) var(--gp-ease-inout) infinite alternate; }
.gp-lvl-2 { animation-delay: -2.9s; }
[data-node="ngl_storage"] .gp-lvl { animation-delay: -4.2s; }
@keyframes gp-breathe-lvl { from { transform: translateY(-0.9px); } to { transform: translateY(0.9px); } }

/* --------------------------------------------------------------------------
   Tooltip chip
   -------------------------------------------------------------------------- */
.gp-tip { position: absolute; z-index: 30; transform: translate(-50%, -100%); background: rgba(11, 46, 79, 0.95); color: #fff; border-radius: 9px; padding: 9px 14px; font-size: 14.5px; line-height: 1.45; pointer-events: none; box-shadow: 0 10px 24px rgba(1, 42, 66, 0.30); max-width: 270px; text-align: center; }
.gp-tip--below { transform: translate(-50%, 0); }
.gp-tip strong { display: block; font-family: 'Montserrat', sans-serif; font-size: 13.5px; letter-spacing: .02em; margin-bottom: 1px; }
.gp-tip span { opacity: .85; font-size: 13px; }

/* --------------------------------------------------------------------------
   Trace chip
   -------------------------------------------------------------------------- */
/* Sits in the canvas's empty lower-left region — never over the diagram */
.gp-tracechip { position: absolute; bottom: 18px; left: 20px; z-index: 25; display: flex; align-items: center; gap: 10px; background: #fff; border: 1px solid var(--gp-line); border-radius: 999px; padding: 8px 10px 8px 16px; box-shadow: 0 12px 28px rgba(1, 42, 66, 0.18); font-size: 13.5px; }
@media (max-width: 767px) {
  .gp-tracechip { position: fixed; bottom: 14px; left: 50%; transform: translateX(-50%); z-index: 60; }
}
.gp-tracechip-swatch { width: 12px; height: 12px; border-radius: 50%; background: var(--gp-muted); }
.gp-tracechip-swatch[data-color="export"] { background: var(--gp-export); }
.gp-tracechip-swatch[data-color="lpg"] { background: var(--gp-lpg); }
.gp-tracechip-swatch[data-color="ngl"] { background: var(--gp-ngl); }
.gp-tracechip-label { font-weight: 600; color: var(--gp-ink); font-size: 14.5px; }
.gp-tracechip-clear { border: 0; background: var(--gp-canvas); color: var(--gp-muted); border-radius: 999px; padding: 5px 12px; font-size: 12.5px; cursor: pointer; transition: background var(--gp-t-micro), color var(--gp-t-micro); }
.gp-tracechip-clear:hover { background: var(--gp-navy); color: #fff; }

/* --------------------------------------------------------------------------
   DetailPanel
   -------------------------------------------------------------------------- */
.gp-panel { position: absolute; top: 14px; bottom: 14px; right: 14px; width: 360px; max-width: calc(100% - 28px); z-index: 40; background: #fff; border: 1px solid var(--gp-line); border-radius: 14px; box-shadow: 0 24px 60px rgba(1, 42, 66, 0.28); display: flex; flex-direction: column; animation: gp-panel-in var(--gp-t-panel) var(--gp-ease-out); }
.gp-panel[dir="rtl"] { right: auto; left: 14px; }
@keyframes gp-panel-in { from { opacity: 0; transform: translateX(24px); } }
.gp-panel[dir="rtl"] { animation-name: gp-panel-in-rtl; }
@keyframes gp-panel-in-rtl { from { opacity: 0; transform: translateX(-24px); } }
.gp-panel:focus { outline: none; }
.gp-panel-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; padding: 18px 20px 14px; border-bottom: 1px solid var(--gp-line); }
.gp-panel-kicker { font-family: 'Montserrat', sans-serif; font-size: 11.5px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--gp-gold); margin: 0 0 4px; }
.gp-panel-title { font-family: 'Montserrat', sans-serif; font-size: 22px; font-weight: 700; color: var(--gp-ink); margin: 0; line-height: 1.25; }
.gp-panel-close { flex: none; width: 32px; height: 32px; border: 0; border-radius: 9px; background: var(--gp-canvas); color: var(--gp-muted); font-size: 19px; line-height: 1; cursor: pointer; transition: background var(--gp-t-micro), color var(--gp-t-micro); }
.gp-panel-close:hover { background: var(--gp-navy); color: #fff; }
.gp-panel-scroll { flex: 1; overflow-y: auto; padding: 16px 20px; }
.gp-panel-desc { font-size: 15px; line-height: 1.75; color: #3f4d56; margin: 0 0 16px; }
.gp-panel-io { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 16px; }
.gp-io h4, .gp-params h4 { font-family: 'Montserrat', sans-serif; font-size: 11.5px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--gp-muted); margin: 0 0 7px; }
.gp-io ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 5px; }
.gp-io li { font-size: 13.5px; line-height: 1.4; color: var(--gp-ink); background: var(--gp-canvas); border: 1px solid var(--gp-line); border-radius: 8px; padding: 6px 10px; }
.gp-io-out li { border-inline-start: 3px solid var(--gp-gold); }
.gp-params dl { margin: 0; }
.gp-params div { display: flex; justify-content: space-between; gap: 12px; padding: 7px 0; border-bottom: 1px dashed var(--gp-line); }
.gp-params div:last-child { border-bottom: 0; }
.gp-params dt { font-size: 13.5px; color: var(--gp-muted); margin: 0; }
.gp-params dd { font-size: 13.5px; font-weight: 600; color: var(--gp-ink); margin: 0; text-align: end; }
.gp-panel-nav { display: flex; gap: 10px; padding: 12px 20px 16px; border-top: 1px solid var(--gp-line); }
.gp-panel-nav button { flex: 1; border: 1px solid var(--gp-line); background: #fff; color: var(--gp-blue); font-family: 'Montserrat', sans-serif; font-size: 13.5px; font-weight: 600; border-radius: 10px; padding: 10px 8px; cursor: pointer; transition: background var(--gp-t-micro), color var(--gp-t-micro), border-color var(--gp-t-micro); }
.gp-panel-nav button:hover:not(:disabled) { background: var(--gp-blue); border-color: var(--gp-blue); color: #fff; }
.gp-panel-nav button:disabled { opacity: .4; cursor: default; }

@media (max-width: 767px) {
  .gp-panel { position: fixed; top: auto; left: 10px !important; right: 10px !important; bottom: 10px; width: auto; max-height: 78vh; animation-name: gp-sheet-in; }
  @keyframes gp-sheet-in { from { opacity: 0; transform: translateY(28px); } }
}

/* --------------------------------------------------------------------------
   In-canvas utilities containment + products legend (desktop SVG)
   -------------------------------------------------------------------------- */
.gp-utilbox-frame { fill: rgba(246, 249, 251, .6); stroke: rgba(192, 57, 43, .55); stroke-width: 2; stroke-dasharray: 7 6; }
.gp-utilbox-title { font-size: 14.5px; font-weight: 700; letter-spacing: .14em; fill: var(--gp-utility); }
.gp-utilbox-note { font-family: 'Roboto', sans-serif; font-size: 12.5px; fill: var(--gp-muted); }
.gp-uchip rect { fill: #fff; stroke: var(--gp-line); stroke-width: 1.2; }
/* Hand-drawn utility glyphs (no icon font) — same stroke language as equipment */
.gp-uglyph { color: var(--gp-utility); }
.gp-uglyph * { fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.gp-uglyph .gp-g-soft { opacity: .5; stroke-width: 1.5; }
.gp-uflame { fill: currentColor !important; stroke: none !important; animation: gp-flicker 1.8s ease-in-out infinite; }
.gp-utname { font-size: 12.5px; font-weight: 700; letter-spacing: .04em; fill: var(--gp-ink); }

/* Products legend — larger rows carrying the product's own equipment icon */
.gp-legend-frame { fill: #fff; stroke: var(--gp-line); stroke-width: 1.25; }
.gp-legend-title { font-size: 14.5px; font-weight: 700; letter-spacing: .14em; fill: var(--gp-navy); }
.gp-legend-count { font-size: 13px; font-weight: 700; fill: var(--gp-muted); }
.gp-legend-item { cursor: pointer; }
.gp-legend-item:focus { outline: none; }
.gp-legend-hit { fill: #fff; stroke: var(--gp-line); stroke-width: 1.2; transition: fill var(--gp-t-micro), stroke var(--gp-t-micro); }
.gp-legend-item[data-color="export"] .gp-legend-hit { fill: #EDF6F1; stroke: rgba(30, 125, 70, .40); }
.gp-legend-item[data-color="lpg"] .gp-legend-hit { fill: #F7F0F9; stroke: rgba(123, 45, 142, .38); }
.gp-legend-item[data-color="ngl"] .gp-legend-hit { fill: #F7F1EA; stroke: rgba(122, 74, 33, .38); }
.gp-legend-item:hover .gp-legend-hit { stroke-width: 2; }
.gp-legend-item:focus-visible .gp-legend-hit { stroke: var(--gp-gold); stroke-width: 2.5; }
.gp-legend-item[data-color="export"] .gp-legend-bar, .gp-legend-item[data-color="export"] .gp-legend-name { fill: var(--gp-export); }
.gp-legend-item[data-color="lpg"] .gp-legend-bar, .gp-legend-item[data-color="lpg"] .gp-legend-name { fill: var(--gp-lpg); }
.gp-legend-item[data-color="ngl"] .gp-legend-bar, .gp-legend-item[data-color="ngl"] .gp-legend-name { fill: var(--gp-ngl); }
.gp-legend-item[data-color="export"] .gp-legend-glyph { color: var(--gp-export); }
.gp-legend-item[data-color="lpg"] .gp-legend-glyph { color: var(--gp-lpg); }
.gp-legend-item[data-color="ngl"] .gp-legend-glyph { color: var(--gp-ngl); }
.gp-legend-glyph * { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.gp-legend-glyph .gp-g-soft { opacity: .45; stroke-width: 1.6; }
.gp-legend-name { font-size: 16px; font-weight: 700; letter-spacing: .03em; }
.gp-legend-dest { font-family: 'Roboto', sans-serif; font-size: 12.5px; fill: var(--gp-muted); }
/* Keep the furniture legible during trace/hover dim states */
.gp-tracing .gp-utilbox, .gp-hot .gp-utilbox { opacity: .5; }
.gp-utilbox, .gp-legend { transition: opacity var(--gp-t-state) var(--gp-ease-inout); }

/* --------------------------------------------------------------------------
   Utilities strip (HTML) — mobile only; desktop has the in-canvas box
   -------------------------------------------------------------------------- */
.gp-utilities { display: none; margin-top: 22px; background: #fff; border: 2px dashed rgba(192, 57, 43, 0.55); border-radius: 14px; padding: 16px 20px 18px; }
@media (max-width: 767px) { .gp-utilities { display: block; } }
.gp-utilities-head { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; margin-bottom: 12px; }
.gp-utilities-head h3 { font-family: 'Montserrat', sans-serif; font-size: 14px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--gp-utility); margin: 0; }
.gp-utilities-head p { font-size: 13.5px; color: var(--gp-muted); margin: 0; flex: 1; }
.gp-utilities-toggle { border: 1px solid var(--gp-line); background: var(--gp-canvas); color: var(--gp-blue); font-size: 12px; font-weight: 600; border-radius: 999px; padding: 4px 12px; cursor: pointer; transition: background var(--gp-t-micro), color var(--gp-t-micro); }
.gp-utilities-toggle:hover { background: var(--gp-blue); color: #fff; }
.gp-utilities-list { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(6, 1fr); gap: 10px; }
.gp-chip { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 6px; background: var(--gp-canvas); border: 1px solid var(--gp-line); border-radius: 11px; padding: 12px 8px; transition: border-color var(--gp-t-micro), box-shadow var(--gp-t-micro); }
.gp-chip:hover, .gp-chip:focus-visible { border-color: rgba(192, 57, 43, 0.5); box-shadow: var(--gp-shadow-rest); outline: none; }
.gp-chip-icon { width: 22px; height: 22px; display: block; }
.gp-chip-name { font-family: 'Montserrat', sans-serif; font-size: 12.5px; font-weight: 700; letter-spacing: .03em; color: var(--gp-ink); text-transform: uppercase; }
.gp-chip-blurb { font-size: 12.5px; line-height: 1.5; color: var(--gp-muted); display: none; }
.gp-utilities.is-open .gp-chip-blurb, .gp-chip:hover .gp-chip-blurb, .gp-chip:focus-visible .gp-chip-blurb { display: block; }
@keyframes gp-flicker { 0%, 100% { opacity: 1; } 42% { opacity: .55; } 58% { opacity: .9; } 71% { opacity: .6; } }
@media (max-width: 991px) { .gp-utilities-list { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 575px) { .gp-utilities-list { grid-template-columns: repeat(2, 1fr); } }

/* --------------------------------------------------------------------------
   Prose fallback ("read as text")
   -------------------------------------------------------------------------- */
.gp-prose { margin-top: 18px; background: #fff; border: 1px solid var(--gp-line); border-radius: 12px; padding: 14px 20px; }
.gp-prose summary { font-family: 'Montserrat', sans-serif; font-size: 14.5px; font-weight: 600; color: var(--gp-blue); cursor: pointer; }
.gp-prose[open] summary { margin-bottom: 10px; }
.gp-prose ol, .gp-prose ul { margin: 0 0 12px; padding-inline-start: 22px; }
.gp-prose li { font-size: 14.5px; line-height: 1.75; color: #3f4d56; margin-bottom: 8px; }
.gp-prose h4 { font-family: 'Montserrat', sans-serif; font-size: 12px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--gp-ink); margin: 14px 0 8px; }
.gp-prose p { font-size: 13px; color: var(--gp-muted); margin: 0 0 8px; }

/* --------------------------------------------------------------------------
   Reduced motion — everything still communicates, nothing moves
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .gpx *, .gpx *:before, .gpx *:after { animation: none !important; transition: none !important; }
  .gp-js:not(.gp-in) .gp-node { opacity: 1; transform: none; }
  .gp-js:not(.gp-in) .gp-pipe { stroke-dasharray: none; stroke-dashoffset: 0; }
  .gp-js:not(.gp-in) .gp-arrow { opacity: 1; }
  /* Direction stays legible without motion: static dashes + arrowheads */
  .gp-flow { opacity: 1 !important; stroke-opacity: .6; }
  .gp-flow-glow { display: none; }
  .gp-arrowhead { opacity: 1; }
  .gp-tracing .is-route .gp-traceline { opacity: 1; stroke-dashoffset: 0; }
}
