/* ============================================================
   SVG FLOOR PLAN ELEMENTS
   Covers: canvas border, floor tiles, grid labels, racks,
   patch panels, pathways (fiber + copper), cable links,
   alignment guides, airflow indicators
   ============================================================ */

/* --- Canvas --- */


/* --- Floor tiles & grid --- */

.floorplan-frame {
    fill: #c8c8c8;
    pointer-events: none;
}

.floorplan-frame--fiber    { fill: rgba(241, 196, 15,  0.22); }
.floorplan-frame--copper   { fill: rgba(100, 100, 100, 0.18); }
.floorplan-frame--active   { fill: var(--dc-c-accent); }
.floorplan-frame--backdrop { fill: rgba(33,  150, 243, 0.18); }
.floorplan-frame--static   { fill: #555; }

/* --- Static rects (AC, columns, UPS, etc.) --- */
.static-rect {
    fill: rgba(90, 90, 90, 0.35);
    stroke: #444;
    stroke-width: 1.5;
    stroke-dasharray: 5 3;
}
.static-rect--preview {
    fill: rgba(90, 90, 90, 0.45);
    stroke: #333;
    stroke-width: 1.5;
    stroke-dasharray: 4 3;
}
.static-rect-label {
    font-family: Arial, sans-serif;
    font-size: 11px;
    font-weight: 600;
    fill: #444;
    text-anchor: middle;
    dominant-baseline: middle;
    pointer-events: none;
    user-select: none;
}
.static-rect-sublabel {
    font-family: Arial, sans-serif;
    font-size: 9px;
    font-weight: 400;
    fill: #555;
    text-anchor: middle;
    dominant-baseline: middle;
    pointer-events: none;
    user-select: none;
}
.static-rect-handle {
    fill: #fff;
    stroke: #888;
    stroke-width: 1;
    /* Size is anti-scaled in JS; the outline needs the same treatment or it
       thickens as you zoom in */
    vector-effect: non-scaling-stroke;
}
.static-rect-handle:hover {
    fill: #e0e0e0;
    stroke: #555;
}

/* --- Floor resize overlay --- */
.resize-overlay .resize-outline,
.resize-overlay .resize-handle { display: none; }

.resize-overlay:hover .resize-outline,
.resize-overlay:hover .resize-handle { display: block; }

.resize-outline {
    fill: none;
    stroke: #5090d0;
    stroke-width: 1.5;
    stroke-dasharray: 5 3;
}

.resize-handle {
    fill: #fff;
    stroke: #5090d0;
    stroke-width: 1.5;
    /* Size is anti-scaled in JS; the outline needs the same treatment or it
       thickens as you zoom in */
    vector-effect: non-scaling-stroke;
}

.resize-detector {
    pointer-events: fill;
    cursor: grab;
}

body.floor-zone-dragging .resize-overlay .resize-outline,
body.floor-zone-dragging .resize-overlay .resize-handle { display: none; }
body.floor-zone-dragging .resize-detector { pointer-events: none; }

/* The whole floor of a zone in one element: the fill is the tile pattern, the
   stroke closes its right and bottom edges (the pattern draws left and top of each
   cell). Colours live in the pattern itself — see the defs in drawFloorPlan(). */
.floor-tiles {
    fill: url(#floorTilePattern);
    stroke: #d0d0d0;
    stroke-width: 0.5;
}

.has-backdrop .floor-tiles {
    fill: url(#floorTileBackdropPattern);
}

.zone-name-label {
    font-family: Arial, sans-serif;
    font-size: 11px;
    font-weight: 600;
    fill: #555;
    text-anchor: start;
    pointer-events: all;
    cursor: pointer;
    user-select: none;
}

.zone-name-label--active {
    fill: #2c8a77;
}

.grid-label {
    font-family: Arial, sans-serif;
    font-size: 10px;
    fill: #666;
    text-anchor: middle;
    cursor: default;
    user-select: none;
}

.grid-label:hover {
    fill: #3498db;
}

/* --- Racks --- */

.rack {
    cursor: move;
    transition: opacity 0.2s;
    opacity: 0.85; /* Slight transparency to see trays under the rack */
}

.rack:hover {
    opacity: 0.7; /* More transparency on hover */
}

.rack-selection-outline {
    fill: none;
    stroke: var(--dc-c-accent);
    stroke-width: 3;
    pointer-events: none;
}

.rack.rack--dragging {
    opacity: 0.25;
}

.rack-group-outline {
    fill: none;
    stroke: var(--dc-c-accent);
    stroke-width: 2;
    /* Shared dash token — see --rack-dash (rack-styles.css). One rect is fine here:
       this outline is padded away from the rack bodies, so it never lies on another
       dashed line the way two touching Reserved cabinets do. */
    stroke-dasharray: var(--rack-dash);
    pointer-events: none;
}

.rack.selectable {
    cursor: pointer;
}

/* .rack-reserved-edge is listed explicitly: a Reserved body is a strokeless, fill:none
   rect, so its outline lives in <line> elements and would miss the hover cue. */
.rack.selectable:hover rect,
.rack.selectable:hover .rack-reserved-edge {
    filter: brightness(1.2);
}

.rack.link-selected rect {
    stroke: var(--dc-c-error);
    stroke-width: 4;
}

/* --- Rack / panel text labels --- */

.rack-label {
    font-family: Arial, sans-serif;
    font-size: 11px;
    fill: #333;
    text-anchor: middle;
    pointer-events: none;
    font-weight: 500;
    user-select: none;
}

.coordinate-label {
    font-family: Arial, sans-serif;
    font-size: 9px;
    fill: var(--dc-c-muted);
    text-anchor: start;
    pointer-events: none;
    font-weight: 500;
    letter-spacing: 0.02em;
    user-select: none;
}

.panel-type-label {
    font-family: Arial, sans-serif;
    font-size: 8px;
    fill: var(--dc-c-dark);
    text-anchor: middle;
    pointer-events: none;
    font-weight: 600;
    user-select: none;
}

/* --- Inline rack name editor (SVG overlay) --- */

#nameEditInput {
    position: absolute;
    padding: 6px;
    border: 2px solid #3498db;
    border-radius: 4px;
    font-size: 11px;
    z-index: 100;
    display: none;
}

/* A zone that is not the active one is greyed by this, laid over its contents —
   see the comment in drawFloorPlan(). It must never take the mouse: activating the
   zone is the job of .inactive-zone-overlay, which sits above it. */
.inactive-zone-veil {
    fill: rgba(128, 128, 128, 0.15);
    pointer-events: none;
}

/* --- Alignment guides --- */

.alignment-guide {
    stroke: #3498db;
    stroke-width: 1;
    stroke-dasharray: 3,3;
    fill: none;
    pointer-events: none;
}

.alignment-corner {
    fill: var(--dc-c-error);
    stroke: white;
    stroke-width: 1;
    pointer-events: none;
    opacity: 0.8;
}

/* --- Airflow indicators --- */

.airflow-arrow {
    pointer-events: none;
}

.airflow-front {
    fill: #3498db;
}

.airflow-rear {
    fill: var(--dc-c-error);
}

/* --- Pathway grid --- */

.pathway-grid-line {
    stroke: #aaa;
    stroke-width: 0.8;
    stroke-dasharray: 2,2;
    fill: none;
    pointer-events: none;
}

/* Main 600 mm tile edges, redrawn over the pathway grid so tiles stay visible. */
.floor-tile-major-line {
    stroke: #9098a0;
    stroke-width: 1;
    fill: none;
    pointer-events: none;
}

/* --- Fiber cable trays (yellow / orange drop / red invalid) --- */

/* A whole tray of one class in a single <path>, one subpath per cell — so there is
   no longer an element per cell to hover, and nothing to click on either: tray
   editing goes through its own delegated hit-area (_appendTrayEditOverlay), which
   covers these and carries its own crosshair cursor. */
.pathway-cell {
    fill: #ffeb3b;
    opacity: 0.6;
    /* Deeper than the #fdd835 the per-cell rects carried. Two translucent rects used
       to stack their shared edge to ~0.84 alpha, one path draws it once at 0.6 — this
       colour brings the cell grid back to the density it had. Picked by measuring the
       two renderings against each other, not by eye. */
    stroke: #f5b700;
    stroke-width: 1;
}

.pathway-cell.pathway-cell--drop    { fill: #ff9800; stroke: #f57c00; }
.pathway-cell.pathway-cell--invalid { fill: #ef5350; stroke: #c62828; }

/* Spurs the tool hung off the run by itself (js/tray-drops.js): an outline laid over
   the cell, never a fill of its own. The cell keeps the colour its classification gives
   it — orange over a panel, yellow in the aisle — and the dashes answer the separate
   question of who drew it. One blue for both tray types — it marks authorship, which is
   the same fact whether the cell carries fibre or copper. */
.tray-cell-auto {
    fill: none;
    stroke: #1565c0;
    /* Same weight and dash rhythm as the collision overlay, which is the other thing on
       the plan drawn as an outline over something else and has to read at any zoom. */
    stroke-width: 2.5;
    stroke-dasharray: 5 3;
    stroke-linecap: square;
    /* Without this the marker thins out as the plan is zoomed away from and disappears at
       exactly the zoom a whole floor is read at — which is when "who drew this cell?" is
       the question being asked. */
    vector-effect: non-scaling-stroke;
    pointer-events: none;
}

.pathway-cell-overlay {
    fill: transparent;
    cursor: pointer;
    stroke: none;
}

.pathway-cell-overlay:hover {
    fill: rgba(255, 235, 59, 0.2);
}

/* --- Copper cable trays (patterned) --- */

.copper-pathway-cell {
    fill: url(#copperTrayPattern);
    opacity: 0.3;
    pointer-events: none;
    /* Black rather than #3a3a3a for the same reason .pathway-cell went deeper: the
       shared edges are drawn once now instead of twice. The two renderings are
       indistinguishable here anyway — the tray texture carries the eye — this is just
       the closest match of the ones measured. */
    stroke: #000000;
    stroke-width: 0.2;
}

.copper-pathway-cell-overlay {
    fill: transparent;
    cursor: pointer;
    stroke: none;
}

.copper-pathway-cell-overlay:hover {
    fill: rgba(85, 85, 85, 0.2);
}

/* --- Rack links (routed cable lines) --- */

.rack-link {
    stroke: var(--dc-c-error);
    stroke-width: 3;
    fill: none;
    pointer-events: stroke;
    cursor: pointer;
    stroke-linejoin: round;
    stroke-linecap: round;
}

.rack-link:hover {
    stroke-width: 4;
}

.rack-link--no-route {
    stroke-width: 2;
    stroke-dasharray: 6 4;
    opacity: 0.55;
}

.rack-link.highlighted {
    stroke: #ff4422;
    stroke-width: 6;
    filter: drop-shadow(0 0 4px rgba(255, 80, 30, 0.85));
}

#floorplan.has-highlight .rack-link:not(.highlighted) {
    opacity: 0.12;
    transition: opacity 0.2s;
}

#floorplan.has-highlight .rack-link.highlighted {
    transition: opacity 0.2s;
}

/* --- Link endpoint drag handles --- */

.link-endpoint-handle-dot {
    stroke-width: 2;
    pointer-events: all;
    filter: drop-shadow(0 0 3px rgba(0, 0, 0, 0.4));
    transition: r 0.1s;
}

.link-endpoint-handle:hover .link-endpoint-handle-dot {
    filter: drop-shadow(0 0 5px rgba(0, 0, 0, 0.55));
}

.link-endpoint-rubber-line {
    stroke: #ff4422;
    stroke-width: 2;
    stroke-dasharray: 6 4;
    fill: none;
    pointer-events: none;
    opacity: 0.8;
}

.link-endpoint-hover-target {
    fill: rgba(255, 68, 34, 0.18);
    stroke: #ff4422;
    stroke-width: 2;
    pointer-events: none;
    transform-box: fill-box;
    transform-origin: center;
    animation: link-endpoint-pulse 0.7s ease-in-out infinite alternate;
}

@keyframes link-endpoint-pulse {
    from { transform: scale(1);    opacity: 0.9; }
    to   { transform: scale(1.35); opacity: 0.45; }
}

/* --- Patch panels --- */

.patch-panel {
    fill: #34495e;
    stroke: var(--dc-c-dark);
    stroke-width: 1;
    rx: 2;
    ry: 2;
    cursor: default;
    opacity: 0.3;
    user-select: none;
}

.patch-panel.front {
    fill: #3498db;
    stroke: var(--dc-c-info);
}

.patch-panel.rear {
    fill: var(--dc-c-error);
    stroke: var(--dc-c-error-hover);
}

/* Panels with links - darker colors and locked */
.patch-panel.front.has-links {
    fill: #1f618d;
    stroke: #154360;
    cursor: pointer !important;
    opacity: 1;
}

.patch-panel.rear.has-links {
    fill: #a93226;
    stroke: #78281f;
    cursor: pointer !important;
    opacity: 1;
}

.patch-panel:hover {
    opacity: 0.5;
}

/* No hover effect for panels with links to show they're locked */
.patch-panel.has-links:hover {
    opacity: 1;
    /* Add subtle border highlight to indicate it's clickable but not draggable */
    stroke-width: 2;
}

/* ODF LISA-L+R panels — left=blue (same as front), right=red (same as rear) */
.patch-panel.left  { fill: #3498db; stroke: var(--dc-c-info); }
.patch-panel.right { fill: var(--dc-c-error); stroke: var(--dc-c-error-hover); }
.patch-panel.left.has-links  { fill: #1f618d; stroke: #154360; cursor: pointer !important; opacity: 1; }
.patch-panel.right.has-links { fill: #a93226; stroke: #78281f; cursor: pointer !important; opacity: 1; }

/* ── Tray load heat map ──────────────────────────────────────────────────────
   The mode answers one question — how much cable runs here — so everything that
   would answer a different one is taken off the picture: links, panel strips,
   waypoints, the backdrop, collision fills. Cabinets stay as faint outlines,
   because a heat map with no cabinets in it cannot be located on the floor. */
#floorplan.tray-load-mode .rack-link,
#floorplan.tray-load-mode .patch-panel,
#floorplan.tray-load-mode .rack-cord-mark,
#floorplan.tray-load-mode .link-waypoint,
#floorplan.tray-load-mode .zone-connection,
#floorplan.tray-load-mode .zone-connection-label,
#floorplan.tray-load-mode .zone-connection-label-bg,
#floorplan.tray-load-mode .rack-service-zone,
#floorplan.tray-load-mode .odf-service-zone,
#floorplan.tray-load-mode .pathway-cell,
#floorplan.tray-load-mode .copper-pathway-cell,
#floorplan.tray-load-mode .tray-cell-auto,
#floorplan.tray-load-mode #collision-overlay,
/* The backdrop is a bare <image>; the rack type icons are the only other ones. */
#floorplan.tray-load-mode image:not(.rack-icon) {
    display: none;
}

/* Faint, and out of the way of the mouse: the cabinets are here to locate the map on
   the floor, not to be dragged while reading it. */
#floorplan.tray-load-mode .rack {
    pointer-events: none;
}

#floorplan.tray-load-mode .rack rect {
    opacity: 0.18;
}

#floorplan.tray-load-mode .rack-label,
#floorplan.tray-load-mode .rack-icon {
    opacity: 0.35;
}

/* Every cell is outlined, loaded or not: the outline is what draws the tray route on an
   otherwise empty floor, and an empty stretch of tray is worth seeing — that is where the
   next cable can still go. */
.tray-load-cell {
    stroke: rgba(38, 50, 62, 0.45);
    stroke-width: 0.7;
    cursor: crosshair;
}

.tray-load-cell:hover {
    stroke: var(--dc-c-dark);
    stroke-width: 1.5;
}

/* Panels picked while building a link. The strip is a few pixels thick and an unpicked
   panel is drawn at 0.3 opacity, so a stroke alone all but disappears — the pick paints the
   whole strip instead, at full opacity, with a halo of its own colour that reads at any
   zoom. Orange is the side the link starts from, green the side(s) it goes to. */
.patch-panel.picked-a,
.patch-panel.picked-b {
    opacity: 1 !important;
    stroke-width: 1.5;
    cursor: pointer !important;
}

.patch-panel.picked-a {
    fill: #f39c12 !important;
    stroke: #7e4d05 !important;
    filter: drop-shadow(0 0 3px rgba(243, 156, 18, 0.9));
}

.patch-panel.picked-b {
    fill: #27ae60 !important;
    stroke: #145a32 !important;
    filter: drop-shadow(0 0 3px rgba(39, 174, 96, 0.9));
}

/* Inactive zone panels — same geometry, reduced opacity */
.patch-panel.inactive-zone-panel { opacity: 0.25; }
.patch-panel.inactive-zone-panel:hover { opacity: 0.45; }
.patch-panel.empty { fill: #bdc3c7 !important; stroke: #95a5a6 !important; cursor: not-allowed !important; }
.odf-empty-warn { font-family: Arial, sans-serif; font-size: 10px; font-weight: 700; fill: var(--dc-c-error); pointer-events: none; user-select: none; }
.odf-cabinet-divider { stroke: var(--dc-c-muted); stroke-width: 1; stroke-dasharray: 3,3; opacity: 0.7; }

/* The edge an ODF is worked from, in the blue a cabinet's front panel is drawn in
   (.patch-panel.front) — the same colour means the same thing on both. A mark only:
   it carries no handlers, so a click in link mode still reaches the rail behind it. */
.odf-face-mark { fill: #3498db; }

/* The cord looped out of a panel: this side of the cabinet has patch cords in it.
   A neutral grey from the scale — the plan spends red on the rear panel and on every
   collision warning, and this mark is news, not a problem. */
.rack-cord-mark {
    fill: none;
    stroke: var(--dc-n-750);
    stroke-width: 1.6;
    stroke-linecap: round;
}

/* --- Inter-zone connection lines --- */

.zone-connection {
    stroke-width: 20;
    fill: none;
    pointer-events: none;
    stroke-linecap: round;
}

.zone-connection--fiber  { stroke: #f1c40f; opacity: 0.45; }
.zone-connection--copper { stroke: #888888; opacity: 0.45; }

.zone-connection--selected { opacity: 0.75; stroke-width: 22; }

.zone-connection-label {
    font-family: Arial, sans-serif;
    font-size: 11px;
    font-weight: 700;
    text-anchor: middle;
    dominant-baseline: middle;
    pointer-events: none;
    user-select: none;
}

.zone-connection-label--fiber  { fill: #9a7000; }
.zone-connection-label--copper { fill: #555; }

.zone-connection-label-bg {
    fill: rgba(255, 255, 255, 0.85);
    stroke: rgba(0, 0, 0, 0.08);
    stroke-width: 1;
}

/* --- Rubber-band line for pending connection --- */

.rubber-band-line {
    stroke-width: 2;
    stroke-dasharray: 8 4;
    fill: none;
    opacity: 0.7;
}

.rubber-band-line--fiber  { stroke: #f1c40f; }
.rubber-band-line--copper { stroke: #888; }

/* --- Exit point hover dots --- */

.exit-connect-dot {
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s;
    stroke: #fff;
    stroke-width: 1.5;
}

.exit-connect-dot--fiber  { fill: #c8940a; }
.exit-connect-dot--copper { fill: #444; }

.exit-point-group:hover .exit-connect-dot,
.exit-point-group--pending .exit-connect-dot {
    opacity: 1;
    pointer-events: all;
}

.exit-connect-dot--active {
    opacity: 1 !important;
    pointer-events: all !important;
    stroke: #fff;
    stroke-width: 2;
    filter: drop-shadow(0 0 4px rgba(0,0,0,0.4));
}

/* Exit already has ≥1 connection — shown on hover in green to signal "add another" */
.exit-point-group--connected:hover .exit-connect-dot--multi,
.exit-point-group--connected .exit-connect-dot--active {
    fill: var(--dc-c-success) !important;
}

/* --- Zone exit indicators (tray cells touching zone boundary) --- */

.zone-exit-indicator--copper {
    fill: #444;
    opacity: 0.8;
}

.zone-exit-indicator--fiber {
    fill: #c8940a;
    opacity: 0.9;
}

.zone-exit-arrow {
    fill: #fff;
    opacity: 0.95;
}

/* ── Hot and cold aisles ───────────────────────────────────────────────────── */
/* The floor between two rows that face each other, coloured by the air that moves
   through it: blue where the fronts meet (cold), red where the backs do (hot).
   Deliberately pale — this is the floor itself, and every other thing on the plan
   has to stay readable standing on top of it. */
.aisle-fill {
    pointer-events: none;
}

.aisle-fill--cold {
    fill: #3498db;
    opacity: 0.13;
}

.aisle-fill--hot {
    fill: #e74c3c;
    opacity: 0.12;
}

/* ── Row indicators ────────────────────────────────────────────────────────── */
.row-indicator {
    /* opacity applied only to badge shape, not text — see .row-indicator-badge */
}

.row-indicator-badge {
    fill: var(--dc-c-accent);
    stroke: #4a9e8c;
    stroke-width: 1;
    opacity: 0.5;
    transition: opacity 0.15s;
}

.row-indicator:hover .row-indicator-badge {
    opacity: 1;
}

/* A selected row. Hover already takes the badge to full opacity, so being selected
   has to say more than that: the outline thickens and darkens, which reads as "on"
   next to a badge the pointer merely happens to be over. */
.row-indicator.selected .row-indicator-badge {
    opacity: 1;
    stroke: #1a5248;
    stroke-width: 2;
}

.row-indicator-label {
    font-size: 9px;
    font-family: Arial, sans-serif;
    fill: #1a5248;
    font-weight: 600;
    pointer-events: all;
    user-select: none;
}

.row-indicator:hover .row-indicator-label {
    fill: #fff;
}
