


.sortable-ghost {
  opacity: 0.4;
}


.sortable-chosen {
  opacity: 0.8;
}


.sortable-drag {
  opacity: 0.8;
}

html {
  font-size: 16px;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

html, body {
  height: 100vh;
  height: -webkit-fill-available;
  margin: 0;
  padding: 0;
  overflow: hidden !important;
  position: fixed;
  width: 100%;
  -webkit-overflow-scrolling: touch;
  font-size: 16px;
}

body {
  color: #e8ded0;
  background-color: #06090c;
  background-image:
    radial-gradient(ellipse 40% 32% at 12% 0%, rgba(61, 112, 121, 0.2) 0%, transparent 55%),
    radial-gradient(ellipse 40% 32% at 100% 100%, rgba(122, 74, 68, 0.16) 0%, transparent 55%),
    radial-gradient(ellipse 42% 34% at 50% 35%, rgba(244, 234, 210, 0.1) 0%, transparent 58%);
  background-size: 100% 100%, 100% 100%, 100% 100%;
  background-repeat: no-repeat, no-repeat, no-repeat;
  background-attachment: fixed;
  position: relative;
}

/* ------------------------------------------------------------------
   Space field — four parallax layers (html::before/::after and
   body::before/::after) so no single element needs more than two
   pseudo-elements. Each star layer is a single pre-rendered 6000x6000
   PNG (roughly 3x a 1920px-wide screen, so drifting never shows an
   obvious repeat) tiled at its own NATIVE pixel size (not stretched to
   a vw/vh or mismatched px box — that inflates/distorts everything
   drawn on it) rather than hundreds/thousands of live CSS gradients —
   animating background-position against that many live gradients was
   forcing a full repaint of the whole stack every frame and stalling
   the page. A static image at native size is just a cheap texture
   blit instead. Drift is driven by `transform: translate3d()`, not
   `background-position` — each element is oversized by one tile length
   past every edge (`inset: -6000px`) so a transform never leaves a gap,
   and translate3d runs on the compositor thread at whatever pace the
   device can actually sustain instead of forcing a main-thread repaint
   every frame, which is what was crashing the tab on mobile. Rear layers
   (smaller, dimmer stars, and the galaxies
   — furthest away) move slowest, front layers (starbursts, brighter
   stars) move fastest — while every layer still moves by exactly one
   tile length (6000px) per cycle, so each loops with zero visible
   reset regardless of its own speed. Regenerate via
   scratchpad/gen_star_images.js and gen_galaxy_image2.js if the
   pattern ever needs to change.
   ------------------------------------------------------------------ */

/* Furthest-back layer (galaxies + its stars) deliberately does not
   drift — at that notional distance, any visible motion within a human
   timescale would be physically absurd, unlike the closer layers where
   drift is just an artistic parallax cue. */
html::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image: url("/starfield-a.png"), url("/galaxy-field.png");
  background-size: 6000px 6000px, 2000px 2000px;
  background-repeat: repeat;
  background-position: 0 0;
}

html::after {
  content: "";
  position: fixed;
  inset: -6000px;
  z-index: -1;
  pointer-events: none;
  background-image: url("/starfield-b.png");
  background-size: 6000px 6000px;
  background-repeat: repeat;
  background-position: 0 0;
  will-change: transform;
  transform: translate3d(0, 0, 0);
  animation: starfield-drift-b 2424s linear infinite;
}

@keyframes starfield-drift-a {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(6000px, 6000px, 0); }
}

@keyframes starfield-drift-b {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(6000px, 6000px, 0); }
}

body::before {
  content: "";
  position: fixed;
  inset: -6000px;
  z-index: -1;
  pointer-events: none;
  background-image: url("/starfield-c.png");
  background-size: 6000px 6000px;
  background-repeat: repeat;
  background-position: 0 0;
  will-change: transform;
  transform: translate3d(0, 0, 0);
  animation: starfield-drift-c 1091s linear infinite;
}

@keyframes starfield-drift-c {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(6000px, 6000px, 0); }
}

body::after {
  content: "";
  position: fixed;
  inset: -6000px;
  z-index: -1;
  pointer-events: none;
  background-image: url("/starfield-d.png");
  background-size: 6000px 6000px;
  background-repeat: repeat;
  background-position: 0 0;
  will-change: transform;
  transform: translate3d(0, 0, 0);
  animation: starfield-drift-d 485s linear infinite, starfield-twinkle 11s ease-in-out infinite;
}

@keyframes starfield-drift-d {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(6000px, 6000px, 0); }
}

/* Very subtle brightness pulse — a handful of stars gently twinkle rather
   than staying perfectly static. */
@keyframes starfield-twinkle {
  0%, 100% { opacity: 0.75; }
  50% { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  html::before,
  html::after,
  body::before,
  body::after {
    animation: none;
  }
}


.sortable-ghost .feature-item,
.sortable-ghost .door-item {
  background-color: #374151 !important;
  border: 2px dashed #6B7280;
}


.sortable-chosen .feature-item,
.sortable-chosen .door-item {
  transform: scale(1.02);
  z-index: 10;
}


.sortable-drag .feature-item,
.sortable-drag .door-item {
  transform: rotate(5deg);
}


.w-4.h-4 {
  font-size: 10px;
  line-height: 1;
}


.feature-item {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}

/* Trix (Post editor) toolbar buttons are hardcoded to black icons/text
   with no background of their own (actiontext.css) — invisible now that
   the page behind them is dark. Inverting just the toolbar flips black
   to white without needing to hand-edit every SVG icon; the link/dialog
   popup already sets its own white background so it's left untouched. */
trix-toolbar {
  filter: invert(1) hue-rotate(180deg);
}


.feature-header {
  display: flex;
  align-items: center;
  flex-shrink: 0;
}

body {
    margin: 0;
    padding: 0;
}


@media (max-width: 768px) {
    
    aside {
        height: auto !important;
        max-height: none !important;
    }
}


body.compact-mode aside {
    height: auto !important;
    max-height: none !important;
}


@media (max-width: 768px) {
    main {
        margin-bottom: 32px !important;
        padding-bottom: 32px !important;
    }
}


body.desktop-mode aside {
    height: 100% !important;
}
.sidebar-container [data-price-breakdown-target="container"]:not(:empty) {
    position: absolute;
    inset: 0; 
    z-index: 1000; 
    display: flex;
    align-items: center;
    justify-content: center;
    background: #ffffff; 

}

.sidebar-container [data-price-breakdown-target="container"]:not(:empty) > * {
    background: #ffffff;
    border: 1px solid rgba(0,0,0,0.12);

    box-shadow: 0 10px 25px rgba(0,0,0,0.25);
    width: 100%; 
    max-width: 100%;
    max-height: 90%;
    overflow: auto;
}


.sidebar-container [data-price-breakdown-target="container"] ol,
.sidebar-container [data-price-breakdown-target="container"] ul {
    margin-bottom: 0 !important; 
}

.sidebar-container [data-price-breakdown-target="container"] li {
    margin: 0 !important; 
}

.sidebar-container [data-price-breakdown-target="container"] li > div {
    margin: 0 !important; 
}


.sidebar-container [data-price-breakdown-target="container"] [data-action*="price-breakdown#close"] {
    position: absolute;


    color: #111827; 
    background: transparent;
    cursor: pointer;
}

.sidebar-container [data-price-breakdown-target="container"] [data-action*="price-breakdown#close"] svg {


}


.sidebar-container {
    
    height: 100%;
}


.sidebar-container { position: relative; }


@media (max-width: 768px) {
    .sidebar-container {
        
        height: auto;
        min-height: 0;
    }
}



.activity-summary {
    display: inline-block !important;
}


main .space-y-3 {
    margin-top: 0 !important;
}

.main_menu_button {
    background-color: #12232a;
    background-image: linear-gradient(180deg, rgba(244, 234, 210, 0.10), rgba(244, 234, 210, 0) 60%);
    color: #f4ead2;
    font-weight: bold;
    font-size: 25px;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 60%);
    border-radius: 5px;
    border: 4px solid #3d7079;
    box-shadow: inset 0 1px 0 rgba(244, 234, 210, 0.15), 0 0 14px rgba(61, 112, 121, 0.35);

    margin: 0 !important;
    display: flex;
    align-items: center;
}

/* Metallic shimmer sweep — a thin diagonal highlight passing left to right
   across the menu button, like light catching brushed metal. Sweeps quickly
   then sits off-screen (invisible) for the rest of the 7s cycle, so both
   the start and loop-back points are hidden and there's no visible jump. */
.main_menu_button::after {
  content: "";
  position: absolute;
  top: 0;
  left: -60%;
  width: 35%;
  height: 100%;
  background: linear-gradient(115deg, transparent 0%, rgba(255, 255, 255, 0.35) 50%, transparent 100%);
  transform: skewX(-20deg);
  pointer-events: none;
  animation: metallic-shimmer 7s ease-in-out infinite;
}

@keyframes metallic-shimmer {
  0% { left: -60%; }
  27.5% { left: 140%; }
  100% { left: 140%; }
}

/* Hamburger icon pulse — a neon-flare attention nudge: grows 50% larger,
   brightens, and shifts to a hot glowing color with a soft halo. The pulse
   itself still takes 2s (unchanged speed); a 2.75s total cycle adds a
   0.75s pause at rest between pulses. */
.hamburger-pulse {
  animation: hamburger-pulse 2.75s ease-in-out infinite;
  transform-origin: center;
}

@keyframes hamburger-pulse {
  0%, 72.73%, 100% {
    transform: scale(1);
    color: #d1d5db;
    filter: brightness(1) drop-shadow(0 0 0 rgba(255, 140, 120, 0));
  }
  36.36% {
    transform: scale(1.5);
    color: #ff8c78;
    filter: brightness(1.9) drop-shadow(0 0 8px rgba(255, 140, 120, 0.95)) drop-shadow(0 0 16px rgba(255, 140, 120, 0.55));
  }
}

@media (prefers-reduced-motion: reduce) {
  .main_menu_button::after,
  .hamburger-pulse {
    animation: none;
  }
}

.banner-logo {
    display: flex;
    justify-content: left;
    align-items: left;
    background-color: #ECDCBA;
}

.navigation_button {
    box-shadow: 2px 4px 4px rgba(0, 0, 0, 40%);
}

.main_content {
    min-height: 80%;
    max-height: 80%;
    min-width: 95%;
    max-width: 95%;
}

.top_nav a {
    color: #09304A;
    text-decoration: none;
    font-weight: bold;
    font-size: 25px;
    text-shadow: 2px 4px 4px rgba(0, 0, 0, 40%);
}

.top_nav a:hover {
    text-decoration: underline;
    color: #A4281A;
}


.active-project {
    
    border-color: #3b82f6 !important; 
    box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.7); 
}


.sidebar-container .space-y-2 {

}


.flex-col > div:first-child {
    margin-top: 0;
    padding-top: 0;
}


.sidebar-container ul.space-y-2 {
    margin-top: 0;
    margin-bottom: 0;
}


.sidebar-container a {

}


.sidebar-container li {

}

.sidebar-container li:last-child {
    margin-bottom: 0 !important; 
}


main .w-full {
    max-width: 100%;
    padding: 0;
}


main .rounded-md {
    margin-left: 0;
    margin-right: 0;
}


.sidebar-container .space-y-2 > * + * {
    margin-top: 0 !important;
}


@media (max-width: 768px) {
    
    .flex-wrap aside {
        width: 100% !important;
        border-right: none !important;
        border-bottom: 1px solid #e5e7eb;
        max-height: 50vh;
        overflow-y: auto;
    }

    
    .flex-wrap main {
        width: 100% !important;

    }
    
    
    .space-y-3 > * + * {

    }
}


@media (max-width: 768px) {
    
    .drawing-panel,
    .diagram-container,
    .svg-container {
        display: none !important;
    }
    
    
    .flex.h-full {
        flex-direction: column !important;
    }
    
    
    .flex.h-full > div:first-child,
    .sidebar-container,
    .flex > div.w-96 {
        width: 100% !important;
        min-width: 100% !important;
        flex: none !important;
    }
    
    .flex.h-full > div:last-child,
    .flex > main,
    .flex > div.h-full.w-full {
        width: 100% !important;
        flex: 1 0 auto !important;
    }
}


body.compact-mode .drawing-panel,
body.compact-mode .diagram-container,
body.compact-mode .svg-container {
    display: none !important;
}

body.compact-mode .flex.h-full {
    flex-direction: column !important;
}

body.compact-mode .flex.h-full > div:first-child,
body.compact-mode .sidebar-container,
body.compact-mode .flex > div.w-96 {
    width: 100% !important;
    min-width: 100% !important;
    flex: none !important;
}

body.compact-mode .flex.h-full > div:last-child,
body.compact-mode .flex > main,
body.compact-mode .flex > div.h-full.w-full {
    width: 100% !important;
    flex: 1 0 auto !important;
}


.sidebar a {
    transition: background-color 0.2s, color 0.2s;
}


.sidebar li a:hover {
    background-color: #3b82f6; 
    color: white;
}


.bg-blue-900, .bg-blue-800 {
  color: #f8f8f8; 
}

.bg-blue-900 h3, .bg-blue-800 h3,
.bg-blue-900 h4, .bg-blue-800 h4 {
  color: white;
}

.bg-blue-900 p, .bg-blue-800 p {
  color: #f8f8f8;
}


.text-blue-300 {
  color: #b4d0ff !important; 
}

.text-blue-200 {
  color: #d1e2ff !important; 
}


.bg-blue-800 input::placeholder,
.bg-blue-800 textarea::placeholder {
  color: #d1e2ff !important; 
  opacity: 0.7;
}


[data-controller="collapsible-section"] .material-icons {
  transition: transform 0.2s ease;
}

[data-controller="collapsible-section"] [data-action="click->collapsible-section#toggle"] {
  cursor: pointer;
  user-select: none;
}

[data-controller="collapsible-section"] [data-action="click->collapsible-section#toggle"]:hover {
  opacity: 0.9;
}

[data-controller="collapsible-section"] [data-action="click->collapsible-section#toggle"]:hover .material-icons {
  color: white;
}


[data-controller="collapsible-section"] h3 {
  transition: color 0.2s ease;
}

[data-controller="collapsible-section"] [data-action="click->collapsible-section#toggle"]:hover h3 {
  text-shadow: 0 0 1px rgba(255, 255, 255, 0.5);
}


.soft-shadow {
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.15);
}


body.compact-mode .dxf-viewer-frame {
    /* TEMP DIAGNOSTIC: forced to 25% of its normal size on purpose, to
       confirm this rule is even the one taking effect on the actual
       device before trying to fix the exact size again. Revert to
       100vw / 100% once confirmed. */
    position: fixed !important;
    top: 52px !important;
    left: 0 !important;
    width: 25vw !important;
    height: calc((100vh - 52px) * 0.25) !important;
    height: calc((100dvh - 52px) * 0.25) !important;
    z-index: 50 !important;
    border: none !important;
    border-radius: 0 !important;
    margin: 0 !important;
}


body.compact-mode #dxf-close-btn {
    display: flex !important;
}

body.desktop-mode #dxf-close-btn {
    display: none !important;
}


#dxf-close-btn {
    z-index: 60 !important;
    position: absolute !important;


    background-color: #ef4444 !important;
    border: none !important;
    cursor: pointer !important;
    touch-action: manipulation !important;
    -webkit-tap-highlight-color: transparent !important;
}

#dxf-close-btn:hover {
    background-color: #dc2626 !important;
    transform: scale(1.05) !important;
}

#dxf-close-btn:active {
    transform: scale(0.95) !important;
}


input.invalid, textarea.invalid {
  border: 1px solid #EF4444 !important;
  background-color: #FBE8E8 !important;
  color: #7a1f1f !important;

  border-color: #EF4444 !important;
  border-style: solid !important;
  border-width: 1px !important;
}


.disabled-readable:disabled,
.disabled-readable[disabled] {
    background-color: rgba(0, 0, 0, 0.05) !important;
    color: inherit !important;
    cursor: not-allowed;
    opacity: 0.9 !important;
    font-weight: 600 !important;
}


.bg-white .disabled-readable:disabled {
    background-color: #1c262d !important;
    color: #9a917f !important;
}

/* ================================================================
   Atomic Age Space theme — global surface/text inversion.
   The app's views hard-code light-theme Tailwind utilities
   (bg-white/gray-*, text-black/gray-*) throughout; overriding those
   utility classes directly here is what makes the dark theme apply
   app-wide without rewriting every view.
   ================================================================ */

.bg-white,
.bg-gray-50,
.bg-gray-100,
.hover\:bg-white:hover,
.hover\:bg-gray-50:hover,
.hover\:bg-gray-100:hover {
  background-color: #141c22 !important;
}

.bg-gray-200,
.bg-gray-300,
.hover\:bg-gray-200:hover {
  background-color: #1c262d !important;
}

/* Smoky, mostly-dark version of Tailwind's bright light-blue panels —
   just enough blue left to read as "blue", not the space background. */
.bg-blue-50,
.bg-blue-100,
.hover\:bg-blue-50:hover,
.hover\:bg-blue-100:hover {
  background-color: #16202c !important;
}

/* ----------------------------------------------------------------
   Sitewide "glow border" — the one place this effect is defined.
   A soft ambient glow plus a thin solid gray border, applied only to
   the dark UI surfaces that already carried the glow (cards, panels,
   pills, nav buttons, dropdowns) — not to every rounded element on
   the site. Add `.ui-glow` to opt any other specific element in.
   Tune the effect in ONE place: this rule. ---------------------- */
.ui-glow,
.bg-white, .bg-gray-50, .bg-gray-100, .bg-gray-200, .bg-gray-300,
.bg-space-panel, .bg-space-void,
.bg-gray-700, .bg-gray-800,
.bg-blue-800, .bg-blue-900,
.bg-green-800, .bg-green-900,
.bg-purple-900,
.bg-accent-teal, .bg-accent-maroon, .bg-accent-gold {
  box-shadow: 0 0 5px 0.5px rgba(255, 255, 255, 0.16) !important;
  border: 0.25px solid #6e6e6e !important;
}

/* Product editor tab headers are plain tabs, not glow panels — even though
   the active/inactive state toggles bg-blue-800/bg-gray-100 (see
   modular_tabs_controller.js), which would otherwise pull them into the
   glow rule above. */
.tab-button {
  box-shadow: none !important;
  border: none !important;
}

.text-black,
.text-gray-900,
.text-gray-800,
.text-gray-700,
.hover\:text-black:hover,
.hover\:text-gray-900:hover,
.hover\:text-gray-800:hover,
.hover\:text-gray-700:hover {
  color: #eee9de !important;
}

.text-gray-600,
.text-gray-500 {
  color: #b7ae9e !important;
}

.border-gray-100,
.border-gray-200,
.border-gray-300,
.divide-gray-100 > :not([hidden]) ~ :not([hidden]),
.divide-gray-200 > :not([hidden]) ~ :not([hidden]) {
  border-color: rgba(61, 112, 121, 0.3) !important;
}

:where(input, textarea, select):not([type="checkbox"]):not([type="radio"]):not([type="range"]):not([type="file"]):not(.invalid) {
  background-color: #1b2229 !important;
  color: #eee9de !important;
  box-shadow: 0 0 5px 0.5px rgba(255, 255, 255, 0.16) !important;
  border: 0.25px solid #6e6e6e !important;
}

:where(input, textarea, select)::placeholder {
  color: #7c8890;
  opacity: 1;
}

:where(input, textarea, select):focus {
  outline-color: #3d7079;
}

input[type="checkbox"],
input[type="radio"] {
  accent-color: #3d7079;
}