#if !defined(NETHER) && !defined(END)
    #define OVERWORLD
#endif

// Returns the horizon-level sky color for the current time of day.
// Used by fog calculations so border fog matches the custom sky horizon.
vec3 customHorizonFogColor(float _sunAngle, vec3 _viewDir, float _rainStrength) {
    // Day/night weights (mirrors gbuffers_skybasic time helpers)
    float _day  = smoothstep(0.50, 0.44, _sunAngle);
    float _rise = smoothstep(0.97, 1.00, _sunAngle);
    float _morn = 1.0 - smoothstep(0.00, 0.05, _sunAngle);
    float _dayF = clamp(_day + _rise + _morn, 0.0, 1.0);

    // Transition (sunrise/sunset)
    float _sunW = clamp(smoothstep(0.96, 1.00, _sunAngle) + (1.0 - smoothstep(0.00, 0.06, _sunAngle)), 0.0, 1.0);
    float _setW = smoothstep(0.44, 0.50, _sunAngle) * (1.0 - smoothstep(0.50, 0.56, _sunAngle));
    float _transW = clamp(_sunW + _setW, 0.0, 1.0);

    // Twilight
    float _afterSet    = smoothstep(0.50, 0.54, _sunAngle) * (1.0 - smoothstep(0.54, 0.62, _sunAngle));
    float _beforeRise  = smoothstep(0.88, 0.93, _sunAngle) * (1.0 - smoothstep(0.97, 1.00, _sunAngle));
    float _twilW = clamp(_afterSet + _beforeRise, 0.0, 1.0);

    // Base horizon blend
    vec3 _dayHorizon   = vec3(SKY_DAY_HORIZON_R,   SKY_DAY_HORIZON_G,   SKY_DAY_HORIZON_B);
    vec3 _nightHorizon = vec3(SKY_NIGHT_HORIZON_R,  SKY_NIGHT_HORIZON_G, SKY_NIGHT_HORIZON_B);
    vec3 _col = mix(_nightHorizon, _dayHorizon, _dayF);

    // Sunset/sunrise tint
    vec3 _sunsetTint = vec3(SKY_SUNSET_R, SKY_SUNSET_G, SKY_SUNSET_B);

    // Reconstruct the world-space sun direction the same way gbuffers_skybasic does.
    float _sunAngleClamped = clamp(_sunAngle < 0.5 ? _sunAngle : 1.0 - _sunAngle, 0.001, 0.499);
    vec3  _worldSunDir = normalize(vec3(
        cos(_sunAngleClamped * 2.0 * 3.14159265),
        sin(_sunAngleClamped * 2.0 * 3.14159265),
        0.0
    ));

    // sunDot: +1 = looking straight at sun, -1 = looking away.
    // Only computed when a real view direction is supplied (len > 0).
    float _dirLen = length(_viewDir);
    float _sunDot = (_dirLen > 0.001) ? dot(normalize(_viewDir), _worldSunDir) : 0.0;

    // Bias: sun-facing horizon gets full tint, anti-sun side gets ~30 % of it.
    float _tintDirBias = _sunDot * 0.35 + 0.65;

    _col = mix(_col, _sunsetTint, _transW * SKY_SUNSET_TINT_STRENGTH * _tintDirBias);

    // Directional hot-spot: a concentrated warm glow right around the sun position,
    float _hotspot = pow(max(_sunDot, 0.0), 1.0 / max(SKY_SUNSET_HOTSPOT_WIDTH, 0.001));
    _col += _sunsetTint * _hotspot * _transW * SKY_SUNSET_HOTSPOT_STRENGTH * 0.5;

    // Twilight tint
    vec3 _twilCol = vec3(SKY_TWILIGHT_R, SKY_TWILIGHT_G, SKY_TWILIGHT_B);
    _col = mix(_col, _twilCol, _twilW * SKY_TWILIGHT_STRENGTH);

    // Rain modulation
    // Desaturate: mix toward luminance-preserving grey.
    float _luma = dot(_col, vec3(0.299, 0.587, 0.114));
    _col = mix(_col, vec3(_luma), _rainStrength * RAIN_SKY_DESATURATE);
    // Darken: scale brightness down.
    _col *= 1.0 - _rainStrength * RAIN_SKY_DARKEN;

    return clamp(_col, 0.0, 1.0);
}

vec3 customHorizonFogColor(float _sunAngle, vec3 _viewDir) {
    return customHorizonFogColor(_sunAngle, _viewDir, 0.0);
}
vec3 customHorizonFogColor(float _sunAngle) {
    return customHorizonFogColor(_sunAngle, vec3(0.0), 0.0);
}

// Returns the current directional sun/moon light color as a function of time
// of day, independent of block light.
float getNightAmount(float _sunAngle) {
    return clamp(smoothstep(0.44, 0.58, _sunAngle) - smoothstep(0.96, 1.00, _sunAngle), 0.0, 1.0);
}

// Iris/OptiFine's moonPhase uniform:
float getMoonPhaseBrightness(int _moonPhase) {
    float _phaseDist = min(float(_moonPhase), 8.0 - float(_moonPhase)); // 0 (full) .. 4 (new)
    float _phaseFrac = _phaseDist / 4.0; // 0 (full) .. 1 (new)
    return mix(1.0, 1.0 - _phaseFrac, MOON_PHASE_INFLUENCE);
}

vec3 getSunlightColor(float _sunAngle) {
    float _nightAmount = getNightAmount(_sunAngle);

    vec3 _dayCol   = vec3(SUNLIGHT_DAY_COLOR_R,   SUNLIGHT_DAY_COLOR_G,   SUNLIGHT_DAY_COLOR_B);
    vec3 _nightCol = vec3(SUNLIGHT_NIGHT_COLOR_R, SUNLIGHT_NIGHT_COLOR_G, SUNLIGHT_NIGHT_COLOR_B);
    vec3 _col = mix(_dayCol, _nightCol, _nightAmount);

    // Wide golden-hour window
    float _sunW  = clamp(smoothstep(0.96, 1.00, _sunAngle) + (1.0 - smoothstep(0.00, 0.06, _sunAngle)), 0.0, 1.0);
    float _setW  = smoothstep(0.44, 0.50, _sunAngle) * (1.0 - smoothstep(0.50, 0.56, _sunAngle));
    float _goldenHour = clamp(_sunW + _setW, 0.0, 1.0);

    vec3 _goldenCol = vec3(SKY_SUNSET_R, SKY_SUNSET_G, SKY_SUNSET_B);
    _col = mix(_col, _goldenCol, _goldenHour * SUNLIGHT_GOLDEN_HOUR_STRENGTH);

    return _col;
}

// Strips vanilla's baked-in lightmap hue down to a pure intensity value.
float lightmapLuma(vec3 _lightmapSample) {
    return dot(_lightmapSample, vec3(0.299, 0.587, 0.114));
}

// Samples the vanilla lightmap purely for its intensity curve (torch falloff +
// sky brightness), then re-tints block light and sky light with fully
// independent custom colors instead of vanilla's baked hue.
vec3 getDecoupledLightmap(sampler2D _lightmap, vec2 coord1, float skyLightFactor, float sBright, vec3 sunlightColor, float ambientOcclusion, float sunAngleIn, int moonPhaseIn) {
    float sBrightForMap = mix(1.0, sBright, skyLightFactor);

    vec3 lMapFull    = texture2D(_lightmap, vec2(coord1.x, coord1.y * sBrightForMap)).rgb;
    vec3 lMapAmbient = texture2D(_lightmap, vec2(0.0,      coord1.y * sBrightForMap)).rgb;

    // Pure intensity curves, vanilla hue discarded.
    float blockIntensity = lightmapLuma(max(lMapFull - lMapAmbient, 0.0));
    float skyIntensity   = lightmapLuma(lMapAmbient);

    vec3 blockCol = vec3(BLOCK_LIGHT_COLOR_R, BLOCK_LIGHT_COLOR_G, BLOCK_LIGHT_COLOR_B);
    vec3 skyCol   = mix(vec3(1.0), sunlightColor, AMBIENT_SKY_TINT_STRENGTH);

    // Day/night ambient boost:
    float moonPhaseMult = getMoonPhaseBrightness(moonPhaseIn);
    float ambientBrightnessMult = mix(DAY_AMBIENT_BRIGHTNESS, NIGHT_AMBIENT_BRIGHTNESS * moonPhaseMult, getNightAmount(sunAngleIn));

    return blockCol * blockIntensity * BLOCK_LIGHT_INTENSITY + skyCol * skyIntensity * ambientOcclusion * ambientBrightnessMult;
}

// Unchanged behaviour for every existing (non-voxy) call site.
vec3 getDecoupledLightmap(sampler2D _lightmap, vec2 coord1, float skyLightFactor, float sBright, vec3 sunlightColor, float sunAngleIn, int moonPhaseIn) {
    return getDecoupledLightmap(_lightmap, coord1, skyLightFactor, sBright, sunlightColor, 1.0, sunAngleIn, moonPhaseIn);
}

vec3 distortShadow(vec3 pos) {
    #if SHADOW_DISTORTION == 1
        float factor = length(pos.xy) + SHADOW_DISTORT_REDUCTION;
        return vec3(pos.xy / factor, pos.z * 0.5);
    #else
        return pos;
    #endif
}
